home *** CD-ROM | disk | FTP | other *** search
/ CD ROM Paradise Collection 4 / CD ROM Paradise Collection 4 1995 Nov.iso / edit / sted102a.zip / SUPERTED.ASM < prev    next >
Assembly Source File  |  1994-05-24  |  78KB  |  2,780 lines

  1. ;======================================================================
  2. ;  SuperTED - and enhanced version of 
  3. ;  TED.ASM -- The Tiny EDitor.
  4. ;  PC Magazine * Tom Kihlken * tktktk
  5. ;  Enhanced by Tony Whyman, McCallum Whyman Associates Ltd
  6. ;----------------------------------------------------------------------
  7. CSEG        SEGMENT
  8.         ASSUME    CS:CSEG, DS:CSEG, ES:CSEG
  9.         ORG    100H        ;Beginning for .COM programs
  10. START:
  11.         JMP    BEGIN
  12.  
  13. ;-----------------------------------------------------------------------
  14. ; Local data area
  15. ;-----------------------------------------------------------------------
  16. MAIL        EQU    0
  17.  
  18. TAB        EQU    9
  19. ESC        EQU    27
  20. DEL        EQU    83
  21. BS        EQU    8
  22. CR        EQU    13
  23. LF        EQU    10
  24. FF        EQU    12
  25. MAX_INDENT    EQU    80
  26. BUFF_SIZE    EQU    65
  27.  
  28. COLOUR_ATR        DB    7
  29. COLOUR_INV        DB    0
  30. COLOUR_SRCH        DB    0
  31. QUOTE_CHAR    DB    ">"
  32.     IFDEF MAIL
  33. WRAP_FLAG    DB    0FFH
  34.     ELSE
  35. WRAP_FLAG    DB    0
  36.     ENDIF
  37. RMARGIN    DB    0
  38. EVEN
  39. WCOLUMNS        DW    0
  40.  
  41. COPYRIGHT    DB    CR,LF,"SuperTED 1.02a - "
  42.         DB    "An Enhancement of PC Magazine's Tiny Editor",CR,LF
  43.         DB    "(c) 1988 Ziff Communications Co.",CR,LF
  44.         DB    "Enhancements (c) 1993, 1994 McCallum Whyman Associates Ltd$",1AH
  45.  
  46. FILE_TOO_BIG    DB      "File too big$"
  47. READ_ERR_MESS   DB      "Read error$"
  48. MEMORY_ERROR    DB      "Not enough memory$"
  49. MISSING_FILENAME DB    "Missing Filename!$"
  50. ABORT_MESS      DB      "Lose Changes Y/N?",0
  51. DEL_PASTE_MESS    DB    "Overwrite Paste Buffer Y/N?",0
  52. IN_FILE_MESS    DB    "Enter Filename?:",0
  53. NO_FILE_MESS    DB    "Cannot Open File",0
  54. TRUNCATE_MESS    DB    "WARNING: File truncated",0
  55. IN_READ_ERR    DB    "Read Error",0
  56. NO_PASTE_MESS    DB    "Buffer Overflow! Paste Fails",0
  57. PAD_MESS    DB    " - ",0
  58. CONTINUE_MESS    DB    "press any key to continue",0
  59. PRINT_CONFIRM    DB    "Print whole file Y/N?"
  60. HELP_ROW    DB    0
  61. HELP_COLS    EQU    4
  62. HELP_OFFSETS    DB    4,28,44,65
  63. HELP_TEXT    DB    0,0,0,0
  64.         DB    "FUNCTION",0,"KEY",0,"FUNCTION",0,"KEY",0
  65.         DB    "========",0,"===",0,"========",0,"===",0
  66.         DB    0,0,0,0
  67.         DB    "Abort",0,"Escape",0,"Screen Right",0,"cntl ->",0
  68.         DB    "Help",0,"F1",0,"Screen Left",0,"cntl <-",0
  69.         DB    "Undo",0,"F2",0,"Top of File",0,"cntl PGUP",0
  70.         DB    "Print (selection)",0,"F3",0,"End of File",0,"cntl PGDN",0
  71.         DB    "Mark",0,"F4",0,"Toggle Insert Mode",0,"INS",0
  72.         DB    "Cut",0,"F5",0,"Toggle Wrap Mode",0,"ALT-W",0
  73.         DB    "Paste",0,"F6",0,"Join Lines",0,"ALT-J",0
  74.         DB    "Paste with Quote",0,"Shift F6",0
  75.         DB    "Force Word Wrap",0,"ALT-S",0
  76.         DB    "Exit",0,"F7",0,"Save File",0,"Shift F7",0
  77.         DB    "Erase to EOL",0,"F8",0,"Replace Text",0,"ALT-L",0
  78.         DB    "Delete Line",0,"F9",0,0,0
  79.         DB    "Undelete Line",0,"F10",0,0,0
  80.         DB    "Find",0,"F11, ALT-F",0,0,0
  81.         DB    "Find Again",0,"Shift F11, Shift ALT-F",0,0,0
  82.         DB    "Import File",0,"F12, ALT-I",0,0,0
  83.         DB    "Import & Quote File",0,"Shift F12, Shift ALT-I",0,0,0
  84.         DB    "Reformat (selection)",0,"ALT-R",0,0,0
  85.         DB    0,0,0,0,-1
  86.  
  87. IN_FILENAME    DB    BUFF_SIZE DUP (0)
  88. SAVE_NAME_BUFF    DB    BUFF_SIZE DUP (0)
  89.  
  90. PROMPT_STRING    DB    "1HELP",0,"2UNDO",0,"3PRINT",0
  91.         DB    "4MARK",0,"5CUT",0,"6PASTE",0,"7EXIT",0
  92.         DB    "8DEL EOL",0,"9DEL L",0,"10UDEL L",0,0
  93. PROMPT_LENGTH    =    $ - OFFSET PROMPT_STRING
  94.  
  95. SAVE_MESS        DB    "Save as: ",0
  96. DOT_$$$        DB    ".$$$",0
  97. DOT_BAK        DB    ".BAK",0
  98. SRCH_PROMPT    DB    "SEARCH STRING> ",0
  99. RPL_PROMPT        DB    "Replace With:",0
  100. SRCH_ERROR        DB    "Search String not found",0
  101. SRCH_STR        DB    BUFF_SIZE DUP (0)
  102. RPL_STR        DB    BUFF_SIZE DUP (0)
  103. SRCH_FLG        DB    0
  104. SRCH_STR_END    DW    0
  105. INDENT_BUFFER    DB    MAX_INDENT DUP (0)
  106.     IFDEF MAIL
  107. SAVE_FILENAME    DB    BUFF_SIZE DUP (0)
  108.     ENDIF
  109. DIRTY_BITS        DB    1
  110. ORGATR        DB    7
  111. INVATR        DB    070H
  112. SRCHATR        DB    0F0H
  113. SAVE_ATR        DB    7
  114. KEYREAD_CODE    DB    10H
  115. KEYSTATUS_CODE    DB    11H
  116. LEFT_MARGIN    DB    0
  117. MARGIN_COUNT    DB    0
  118. INSERT_MODE    DB    -1
  119. MARK_MODE    DB    0
  120. ROWS        DB    23
  121. SAVE_COLUMN    DB    0
  122. SAVE_ROW    DB    0
  123. QUOTE_FLAG    DB    0
  124. LINE_FLAG    DB    0
  125. EVEN
  126. INDENT_SIZE    DW    0
  127. NAME_POINTER    DW    81H
  128. STATUS_REG    DW    ?
  129. VIDEO_SEG    DW    0B000H
  130. LINE_LENGTH    DW    0
  131. UNDO_LENGTH    DW    0
  132. CUR_POSN    DW    0
  133. MARK_START    DW    0FFFFH
  134. MARK_END    DW    0
  135. MARK_HOME    DW    0
  136. TOP_OF_SCREEN    DW    0
  137. CURSOR        DW    0
  138. LAST_CHAR    DW    0
  139. COLUMNSB    LABEL    BYTE
  140. COLUMNS        DW    0
  141. PASTE_SEG    DW    ?
  142. PASTE_SIZE    DW    0
  143. PAGE_PROC    DW    ?
  144. OLDINT24    DD    ?
  145. LAST_WORD    DW    0
  146. DISPATCH_TABLE    DW    OFFSET HELP    ,OFFSET UNDO   ,OFFSET PRINT
  147.         DW    OFFSET MARK    ,OFFSET CUT    ,OFFSET PASTE
  148.         DW    OFFSET EXIT    ,OFFSET DEL_EOL,OFFSET DEL_L
  149.         DW    OFFSET UDEL_L  ,OFFSET BAD_KEY,OFFSET BAD_KEY
  150.         DW    OFFSET HOME    ,OFFSET UP     ,OFFSET PGUP
  151.         DW    OFFSET BAD_KEY ,OFFSET LEFT   ,OFFSET BAD_KEY
  152.         DW    OFFSET RIGHT   ,OFFSET BAD_KEY,OFFSET ENDD
  153.         DW    OFFSET DOWN    ,OFFSET PGDN   ,OFFSET INSERT
  154.         DW    OFFSET DEL_CHAR,OFFSET BAD_KEY,OFFSET BAD_KEY
  155.         DW    OFFSET BAD_KEY ,OFFSET BAD_KEY,OFFSET BAD_KEY
  156.         DW    OFFSET QUOTE
  157.  
  158. ; The following machine instruction removes the desnow delay.  It is
  159. ; inserted into the code for EGA, VGA, and MONO displays.
  160.  
  161. NO_DESNOW = 0EBH + (OFFSET WRITE_IT - OFFSET HWAIT - 2) * 256
  162.  
  163. ;-----------------------------------------------------------------------
  164. ; We start by initialize the display, then allocate memory for the file
  165. ; and paste segments.  Parse the command line for a filename, if one was
  166. ; input, read in the file.  Finally set the INT 23 and 24 vectors.
  167. ;-----------------------------------------------------------------------
  168. BEGIN:
  169.         XOR    AX,AX
  170.         MOV    DS,AX        ;Get a zero into DS
  171.         ASSUME    DS:NOTHING
  172.         MOV    AH,12H
  173.         MOV    BL,10H        ;Get EGA info
  174.         INT    10H
  175.         CMP    BL,10H        ;Did BL change?
  176.         JE    NOT_EGA        ;If not, no EGA in system
  177.         TEST    BYTE PTR DS:[0487H],8    ;Is EGA active?
  178.         JNZ    NOT_EGA
  179.         MOV    WORD PTR CS:HWAIT,NO_DESNOW ;Get rid of desnow
  180.         MOV    AX,DS:[0484H]    ;Get number of rows
  181.         DEC    AL        ;Last row is for prompt line
  182.          MOV    CS:[ROWS],AL    ;Save the number of rows
  183. NOT_EGA:
  184.         MOV    AX,DS:[044AH]    ;Get number of columns
  185.         MOV    CS:COLUMNS,AX    ;and store it
  186.         MOV    BX,WCOLUMNS
  187.         OR    BX,BX
  188.         JNZ    DONE_COLUMNS
  189.         MOV    BH,RMARGIN
  190.         MOV    CL,8
  191.         SAR    BX,CL        ;extend sign bit
  192.         SUB    AX,BX
  193.         MOV    WCOLUMNS,AX
  194. DONE_COLUMNS:
  195.         MOV    AX,DS:[0463H]    ;Address of display card
  196.         ADD    AX,6        ;Add six to get status port
  197.         PUSH    CS
  198.         POP    DS
  199.         ASSUME    DS:CSEG
  200.         MOV    STATUS_REG,AX
  201.         CMP    AX,3BAH        ;Is this a MONO display?
  202.         JNE    COLOUR        ;If not, must be a CGA
  203.         MOV    WORD PTR HWAIT,NO_DESNOW ;Get rid of desnow
  204.         JMP    SHORT MOVE_STACK
  205. COLOUR:
  206.         MOV    VIDEO_SEG,0B800H;Segment for colour card
  207.         XOR    BH,BH        ;Use page zero
  208.         MOV    AH,8        ;Get current attribute
  209.         INT    10H
  210.         MOV    SAVE_ATR,AH    ;Save the original attribute
  211.         MOV    AL,COLOUR_ATR    ;Get colour setting
  212.         CMP    AL,ORGATR    ;New Colours?
  213.         JE    DEFAULT_COLOURS
  214.         MOV    ORGATR,AL    ;Replace monochrome setting
  215.         MOV    AL,COLOUR_INV
  216.         MOV    INVATR,AL
  217.         MOV    AL,COLOUR_SRCH
  218.         MOV    SRCHATR,AL
  219.         JMP    SHORT MOVE_STACK
  220. DEFAULT_COLOURS:
  221.         MOV    ORGATR,AH
  222.         XOR    AH,077H
  223.         MOV    INVATR,AH    ;Save inverse attributes
  224.         XOR    AH,80H        ;set blinking
  225.         MOV    SRCHATR,AH
  226. MOVE_STACK:
  227.         MOV    BX,OFFSET NEW_STACK
  228.         MOV    SP,BX        ;Move the stack downward
  229.         ADD    BX,15
  230.         MOV    CL,4        ;Convert program size to
  231.         SHR    BX,CL        ; paragraphs
  232.         MOV    AH,4AH        ;Deallocate unused memory
  233.         INT    21H
  234.         MOV    BX,1000H    ;Request 64K for file segment
  235.         MOV    AH,48H
  236.         INT    21H
  237.         MOV    ES,AX
  238.         ASSUME    ES:FILE_SEG
  239.         MOV    AH,48H
  240.         INT    21H        ;Request 64K for paste buffer
  241.         JNC    GOT_ENOUGH    ;If enough memory, continue
  242. NOT_ENOUGH:
  243.         MOV    DX,OFFSET MEMORY_ERROR
  244. ERR_EXIT:
  245.         PUSH    CS
  246.         POP    DS
  247.         MOV    AH,9        ;Write the error message
  248.         INT    21H        ;DOS display service
  249.         JMP    EXIT_TO_DOS    ;Exit this program
  250. GOT_ENOUGH:
  251.         MOV    PASTE_SEG,AX    ;Use this for the paste buffer
  252. GET_FILENAME:
  253.         MOV    SI,80H        ;Point to parameters
  254.         MOV    CL,[SI]        ;Get number of characters
  255.         XOR    CH,CH        ;Make it a word
  256.         INC    SI        ;Point to first character
  257.         PUSH    SI
  258.         ADD    SI,CX        ;Point to last character
  259.         MOV    BYTE PTR [SI],0    ;Make it an ASCII string
  260.         POP    SI        ;Get back pointer to filename
  261.         CLD
  262.     IFDEF MAIL
  263.         JCXZ    NO_PARAMS
  264.         JMP    DEL_SPACES
  265. NO_PARAMS:
  266.         MOV    DX,OFFSET MISSING_FILENAME
  267.         JMP    ERR_EXIT    ;exit
  268.     ELSE
  269.         JCXZ    NO_FILENAME    ;If no params, just exit
  270.     ENDIF
  271. DEL_SPACES:    LODSB            ;Get character into AL
  272.         CMP    AL," "        ;Is it a space?
  273.         JNE    FOUND_LETTER
  274.         LOOP    DEL_SPACES
  275. FOUND_LETTER:
  276.         DEC    SI        ;Backup pointer to first letter
  277.         MOV    NAME_POINTER,SI    ;Save pointer to filename
  278.         MOV    DX,SI
  279.         MOV    AX,3D00H    ;Setup to open file
  280.         INT    21H
  281.         JC    NO_FILENAME     ;If we can't open, must be new file
  282. FILE_OPENED:
  283.         PUSH    ES
  284.         POP    DS        ;DS has file segment also
  285.         ASSUME    DS:FILE_SEG
  286.         MOV    BX,AX        ;Get the handle into BX
  287.         XOR    DX,DX        ;Point to file buffer
  288.         MOV    AH,3FH        ;Read service
  289.         MOV    CX,0FFFEH    ;Read almost 64K bytes
  290.         INT    21H
  291.         MOV    DI,AX        ;Number of bytes read in
  292.         JNC    NO_RD_ERR    ;If no error, take jump
  293.         MOV    DX,OFFSET READ_ERR_MESS
  294.         JMP    SHORT ERR_EXIT
  295. NO_RD_ERR:
  296.         MOV    LAST_CHAR,DI    ;Save the file size
  297.         CMP    CX,AX        ;Did the buffer fill?
  298.         MOV    DX,OFFSET FILE_TOO_BIG
  299.         JE    ERR_EXIT    ;If yes, it is too big
  300.         MOV    AH,3EH
  301.         INT    21H        ;Close the file
  302. NO_FILENAME:
  303.         PUSH    ES
  304.         PUSH    ES        ;Save file segment
  305.         MOV    AX,3524H    ;Get INT 24 vector
  306.         INT    21H
  307.         MOV    WORD PTR OLDINT24,BX  ;Store the offset
  308.         MOV    WORD PTR OLDINT24+2,ES;And the segment
  309.  
  310.         PUSH    CS
  311.         POP    DS
  312.         MOV    DX,OFFSET NEWINT24    ;Point to new vector
  313.         MOV    AX,2524H    ;Now change INT 24 vector
  314.         INT    21H    
  315.  
  316.         MOV    DX,OFFSET NEWINT23
  317.         MOV    AX,2523H    ;Set the INT 23 vector also
  318.         INT    21H
  319.  
  320.         POP    ES        ;Get back file segment
  321.         POP    DS
  322.         ASSUME    DS:FILE_SEG, ES:FILE_SEG
  323.         CALL    REDO_PROMPT    ;Draw the prompt line
  324.                     ;check for extended keyboard
  325.         MOV    AH,5        ;write to ext keyboard buffer
  326.         MOV    CX,0FFFFH
  327.         INT    16H        ;write all ones to buffer
  328.         MOV    CX,10H        ;loop up to 16 times
  329. CHECK_EXT:
  330.         PUSH    CX
  331.         MOV    AH,10H        ;read ext keyboard
  332.         INT    16H
  333.         POP    CX
  334.         INC    AX
  335.         JZ    READ_A_KEY    ;AX=0 then 0FFFFH read back
  336.         LOOP    CHECK_EXT
  337.         MOV    KEYREAD_CODE,0    ;set codes for XT
  338.         MOV    KEYSTATUS_CODE,1
  339. ;-----------------------------------------------------------------------
  340. ; Here's the main loop.  It updates the screen, then reads a keystroke.
  341. ;-----------------------------------------------------------------------
  342. READ_A_KEY:
  343.         CMP    MARK_MODE,0    ;Is the mark state on?
  344.         JE    MARK_OFF    ;If not, skip this
  345.         OR    DIRTY_BITS,4    ;Refresh the current row
  346.         MOV    DX,CUR_POSN
  347.         CMP    SAVE_ROW,DH    ;Are we on the save row?
  348.         JE    SAME_ROW    ;If yes, then redo the row only
  349.         MOV    DIRTY_BITS,1    ;Refresh the whole screen
  350. SAME_ROW:
  351.         MOV    AX,CURSOR    ;Get cursor location
  352.         MOV    BX,MARK_HOME    ;Get the anchor mark position
  353.         CMP    AX,BX        ;Moving backward in file?
  354.         JAE    S1
  355.         MOV    MARK_START,AX    ;Switch start and end position
  356.         MOV    MARK_END,BX
  357.         JMP    SHORT MARK_OFF
  358. S1:
  359.         MOV    MARK_END,AX    ;Store start and end marks
  360.         MOV    MARK_START,BX
  361. MARK_OFF:
  362.         MOV    DX,CUR_POSN
  363.         MOV    SAVE_ROW,DH
  364.         CALL    SET_CURSOR    ;Position the cursor
  365.         TEST    DIRTY_BITS,1    ;Look at screen dirty bit
  366.         JZ    SCREEN_OK    ;If zero, screen is OK
  367.         MOV    AH,KEYSTATUS_CODE ;Get keyboard status
  368.         INT    16H        ;Any keys ready?
  369.         JNZ    CURRENT_OK    ;If yes, skip the update
  370.         CALL    DISPLAY_SCREEN    ;Redraw the screen
  371.         MOV    DIRTY_BITS,0    ;Mark screen as OK
  372. SCREEN_OK:
  373.         TEST    DIRTY_BITS,2    ;Is bottom of screen dirty?
  374.         JZ    BOTTOM_OK
  375.         MOV    AH,KEYSTATUS_CODE ;Get keyboard status
  376.         INT    16H        ;Any keys ready?
  377.         JNZ    CURRENT_OK    ;If yes, skip the update
  378.         CALL    DISPLAY_BOTTOM    ;Redraw bottom of screen
  379.         MOV    DIRTY_BITS,0
  380. BOTTOM_OK:
  381.         TEST    DIRTY_BITS,4    ;Is the current line dirty?
  382.         JZ    CURRENT_OK    ;If not, take jump
  383.         CALL    DISPLAY_CURRENT    ;Redraw the current line
  384.         MOV    DIRTY_BITS,0    ;Mark screen as OK
  385. CURRENT_OK:
  386.         MOV    AH,KEYREAD_CODE    ;Read the next key
  387.         INT    16H
  388.         CMP    SRCH_FLG,0
  389.         JE    CKEXT
  390.         NOT    SRCH_FLG
  391.         MOV    DIRTY_BITS,1
  392. CKEXT:
  393.         CMP    AL,0        ;Is this an extended code?
  394.         JE    EXTENDED_CODE
  395.         CMP    AL,0E0H        ;Is this an extended code? (Grey keys)
  396.         JE    EXTENDED_CODE
  397.         CMP    AH,0EH        ;Was it the backspace key?
  398.         JE    BACK_SPACE
  399.         CMP    AH,1        ;Was it an escape?
  400.         JNE    NOT_ESC
  401.         CALL    ABORT
  402.         JMP    READ_A_KEY
  403. NOT_ESC:
  404.         CALL    INSERT_KEY    ;Put this character in the file
  405.         JMP    READ_A_KEY    ;Get another key
  406. BACK_SPACE:
  407.         CMP    CURSOR,0    ;At start of file?
  408.         JE    NEXT_KEY        ;If at start, can't backspace
  409.         CALL    LEFT        ;Move left one space
  410.         CALL    DEL_CHAR    ;And delete the character
  411. NEXT_KEY:
  412.         JMP    READ_A_KEY
  413. EXTENDED_CODE:
  414.         CALL    FUNCTION_DISPATCH
  415.         JMP    READ_A_KEY
  416. ;--------------------------------------------------------------------------------------------
  417. ;  Analyses scan code from special keys andn jumps to appropriate subroutine
  418. ;--------------------------------------------------------------------------------------------
  419. FUNCTION_DISPATCH        PROC NEAR
  420.         CMP    AH,90            ;Is it Shift F7?
  421.         JNE    NOT_SF7
  422.         JMP    SAVE_FILE
  423. NOT_SF7:
  424.         CMP    AH,84H        ;Is it control PgUp?
  425.         JNE    NOT_PAGEUP
  426.         JMP    TOP
  427. NOT_PAGEUP:
  428.         CMP    AH,76H        ;Is it control PgDn?
  429.         JNE    NOT_PAGEDOWN
  430.         JMP    BOTTOM
  431. NOT_PAGEDOWN:
  432.         CMP    AH,134        ;Is it F12?
  433.         JNE    NOT_F12
  434.         JMP    INSERT_FILE
  435. NOT_F12:
  436.         CMP    AH,136        ;Is it Shift F12?
  437.         JNE    NOT_SF12
  438. S_ALTI:
  439.         NOT    QUOTE_FLAG        ;Indicate quote required
  440.         JMP    INSERT_FILE
  441. NOT_SF12:
  442.         CMP    AH,23            ;Is it ALT-I?
  443.         JNE    NOT_ALTI
  444.         MOV    AH,2            ;Test for shift key
  445.         INT    16H
  446.         TEST    AL,3            ;Right or left shift pressed
  447.         JNZ    S_ALTI
  448.         JMP    INSERT_FILE
  449. NOT_ALTI:
  450.         CMP    AH,133        ;Is it f11?
  451.         JNE    NOT_F11
  452.         JMP    FIND_STR
  453. NOT_F11:
  454.         CMP    AH,33        ;Is it ALT-F?
  455.         JNE    NOT_ALTF
  456.         MOV    AH,2            ;Test for shift key
  457.         INT    16H
  458.         TEST    AL,3            ;Right or left shift pressed
  459.         JNZ    S_ALTF
  460.         JMP    FIND_STR
  461. NOT_ALTF:
  462.         CMP    AH,135        ;Is it Shift + F11? 
  463.         JNE    NOT_SF11
  464. S_ALTF:
  465.         JMP    FIND_AGAIN
  466. NOT_SF11:
  467.         CMP    AH,38        ;Is it ALT-L?
  468.         JNE    NOT_ALTL
  469.         MOV    AH,2            ;Test for shift key
  470.         INT    16H
  471.         TEST    AL,3            ;Right or left shift pressed
  472.         JNZ    S_ALTL
  473.         JMP    REPLACE
  474. S_ALTL:
  475.         JMP    RPL_AGAIN
  476. NOT_ALTL:
  477.         CMP    AH,17        ;Is it an ALT-W?
  478.         JNE    NOT_ALTW
  479.         JMP    TOGGLE_WRAP
  480. NOT_ALTW:
  481.         CMP    AH,19        ;Is it an ALT-R?
  482.         JNE    NOT_ALTR
  483.         JMP    REFORMAT
  484. NOT_ALTR:
  485.         CMP    AH,36        ;Is it an ALT-J?
  486.         JNE    NOT_ALTJ
  487.         JMP    JOIN
  488. NOT_ALTJ:
  489.         CMP    AH,31        ;Is it an ALT-S?
  490.         JNE    NOT_ALTS
  491.         JMP    FORMAT_LINE
  492. NOT_ALTS:
  493.         CMP    AH,74H        ;Is it control right arrow?
  494.         JNE    NOT_SHR
  495.         JMP    SH_RIGHT
  496. NOT_SHR:
  497.         CMP    AH,73H        ;Is it control left arrow?
  498.         JNE    NOT_SHL
  499.         JMP    SH_LEFT
  500. NOT_SHL:
  501. ;
  502. ; Remaining keys handled through jump table
  503. ;
  504.         XOR    AL,AL
  505.         CMP    AH,89        ;Skip high numbered keys
  506.         JA    BAD_KEY
  507.         XCHG    AH,AL
  508.         SUB    AL,3BH        ;Also skip low numbered keys
  509.         JC    BAD_KEY
  510.         SHL    AX,1        ;Make the code an offset
  511.         MOV    BX,AX        ;Put offset in BX
  512.         JMP    CS:DISPATCH_TABLE[BX] ;Call the key procedure
  513. BAD_KEY:
  514.         RET            ;Can't dispatch
  515. FUNCTION_DISPATCH    ENDP
  516. ;-----------------------------------------------------------------------------------------------
  517. ;  Flips Wrap mode on and off
  518. ;-----------------------------------------------------------------------------------------------
  519. TOGGLE_WRAP    PROC    NEAR
  520.         NOT    WRAP_FLAG
  521.         CALL    REDO_PROMPT
  522.         RET
  523. TOGGLE_WRAP    ENDP
  524. ;-----------------------------------------------------------------------
  525. ; These two routines shift the display right or left to allow editing
  526. ; files which contain lines longer than 80 columns.
  527. ;-----------------------------------------------------------------------
  528. SH_RIGHT    PROC    NEAR
  529.         CMP    LEFT_MARGIN,255 - 8 ;Past max allowable margin?
  530.         JAE    NO_SHIFT    ;Then can't move any more
  531.         ADD    LEFT_MARGIN,8    ;This moves the margin over
  532. SH_RETURN:
  533.         CALL    CURSOR_COL    ;Compute column for cursor
  534.         MOV    DX,CUR_POSN
  535.         MOV    SAVE_COLUMN,DL    ;Save the current column
  536.         MOV    DIRTY_BITS,1    ;Redraw the screen
  537. NO_SHIFT:
  538.         RET
  539. SH_RIGHT    ENDP
  540.  
  541. SH_LEFT        PROC    NEAR
  542.         CMP    LEFT_MARGIN,0    ;At start of line already?
  543.         JE    NO_SHIFT    ;If yes, then don't shift
  544.         SUB    LEFT_MARGIN,8    ;Move the window over
  545.         JMP    SH_RETURN
  546. SH_LEFT        ENDP
  547. ;----------------------------------------------------------------------
  548. ; This subroutine copies BL to BH and if BL holds lower case graphic then
  549. ; makes BH hold upper case equivalent & vice-versa. Otherwise BL=BH
  550. ;-----------------------------------------------------------------------
  551. CASE_BLIND    PROC    NEAR
  552.         MOV    BH,BL
  553.         CMP    BH,"A"        ;Check to see if before A
  554.         JB    CASE_DONE
  555.         CMP    BH,"z"        ;Check to see if after z
  556.         JA    CASE_DONE
  557.         CMP    BH,"Z"        ;Check to see if upper case
  558.         JA    TEST_LC
  559.         ADD    BL,32        ;Make BL lower case
  560.         RET
  561. TEST_LC:
  562.         CMP    BH,"a"        ;Check to see if lower case
  563.         JB    CASE_DONE
  564.         SUB    BH,32        ;Make BH Uppercase
  565. CASE_DONE:
  566.         RET
  567. CASE_BLIND    ENDP
  568. ;-----------------------------------------------------------------------
  569. ; This subroutine prompts the user for a search pattern and then searches for
  570. ; it in the file from the CURSOR onwards
  571. ;-----------------------------------------------------------------------
  572. FIND_STR    PROC    NEAR
  573.         MOV    SI,OFFSET SRCH_STR    ;Buffer to hold search string
  574.         MOV    DI,OFFSET SRCH_PROMPT    ;Prompt string
  575.         MOV    CX,BUFF_SIZE        ;Max length of search string
  576.         CALL    READ_STRING    ;Prompt user for search string
  577.         JNC    FIND_END    ;Exit if ESC pressed
  578. FIND_AGAIN:                ;Entry point for Find Again
  579.         MOV    SI,CURSOR    ;Start search at CURSOR
  580.         INC    SI        ;and one char later
  581. RPT_LOOP:
  582.         MOV    BL,SRCH_STR    ;get 1st char of search string
  583.         OR    BL,BL        ;Is it a zero?
  584.         JZ    FIND_END    ;Null search string
  585.         CALL    CASE_BLIND    ;Make BH to Upper case, BL to lower
  586.         MOV    CX,LAST_CHAR
  587.         SUB    CX,SI        ;No. of chars to check for match
  588.         JCXZ    FIND_ERROR    ;Exit of EOF
  589. SRCH_LOOP:
  590.         LODSB            ;Get next char to test
  591.         CMP    AL,BL        ;compare with LC
  592.         JE    TEST_REST
  593.         CMP    AL,BH        ;Compare with UC
  594.         JE    TEST_REST
  595.         LOOP    SRCH_LOOP    ;Continue search
  596. FIND_ERROR:
  597.         MOV    SI,OFFSET SRCH_ERROR    ; Report not found
  598.         CALL    ERROR_MESG
  599. FIND_END:
  600.         RET
  601. TEST_REST:
  602.         PUSH    SI
  603.         XOR    DI,DI        ;DI is search string index
  604.         MOV    CX,BUFF_SIZE        ;Maximum search string
  605. TEST_LOOP:
  606.         CMP    SI,LAST_CHAR    ;EOF yet?
  607.         JAE    TEST_FAIL
  608.         INC    DI        ;Next character
  609.         MOV    BL,SRCH_STR[DI]
  610.         OR    BL,BL        ;End of string?
  611.         JZ    SRCH_END    ;String found
  612.         CALL    CASE_BLIND    ;Make BH Upper Case,  BL Lower Case
  613.         LODSB
  614.         CMP    AL,CR        ;CR Found?
  615.         JNE    TEST_CHAR
  616.         LODSB
  617.         CMP    AL,LF        ;Is this EOL
  618.         JNE    TEST_FAIL    ;Fails if embedded CR
  619.         LODSB            ;Skip  CR/LF
  620. TEST_CHAR:
  621.         CMP    AL,BL        ;Check lower case first
  622.         JE    TEST_OK
  623.         CMP    AL,BH        ;Then check upper case
  624.         JNE    TEST_FAIL
  625. TEST_OK:
  626.         LOOP    TEST_LOOP
  627. TEST_FAIL:
  628.         POP    SI
  629.         JMP    SHORT RPT_LOOP    ;continue with search
  630. SRCH_END:
  631.         MOV    SRCH_STR_END,SI    ;Save pointer to EOS
  632.         POP    SI
  633.         DEC    SI
  634.         MOV    CURSOR,SI    ;Cursor now at start of string
  635.         NOT    SRCH_FLG    ;Indicate need to flash display
  636.         MOV    DIRTY_BITS,1    ;Redraw screen
  637.         MOV    UNDO_LENGTH,0    ;reset undo buffer
  638.         MOV    DX,CUR_POSN    ;Locate cursor on current row
  639.         CALL    LOCATE
  640.         RET
  641. FIND_STR    ENDP
  642.  
  643. ;-----------------------------------------------------------------------
  644. ; This searches for selected text and then replces it with specified 
  645. ; text
  646. ;-----------------------------------------------------------------------
  647. REPLACE    PROC    NEAR
  648.         MOV    MARK_MODE,0        ;Mark mode off if replace
  649.         CALL    FIND_STR
  650.         CMP    SRCH_FLG,0        ;Found?
  651.         JNE    RPL_QUERY
  652.         RET
  653. RPL_AGAIN:
  654.         MOV    MARK_MODE,0        ;Mark mode off if replace
  655.         CALL    FIND_AGAIN
  656.         CMP    SRCH_FLG,0        ;Found?
  657.         JNE    RPL_QUERY
  658.         RET
  659. RPL_QUERY:
  660.         CALL    DISPLAY_SCREEN
  661.         MOV    DI,OFFSET RPL_PROMPT
  662.         MOV    SI,OFFSET RPL_STR
  663.         MOV    CX,BUFF_SIZE
  664.         CALL    READ_STRING        ;Get replace string
  665.         JC    RPL_DO
  666.         RET
  667. RPL_DO:
  668.         MOV    CX,LAST_CHAR
  669.         MOV    SI,SRCH_STR_END
  670.         MOV    DI,CURSOR
  671.         SUB    CX,SI        ;Calculate no. of chars to move
  672.         MOV    AX,CX
  673.         ADD    AX,DI
  674.         MOV    LAST_CHAR,AX    ;Adjust file length
  675.         REP    MOVSB        ;Delete selected text
  676.         NOT    SRCH_FLG
  677.         MOV    SI,OFFSET RPL_STR
  678.         MOV    AL,INSERT_MODE
  679.         MOV    INSERT_MODE,-1
  680.         PUSH    AX
  681. RPL_LOOP:                ;insert replacement text
  682.         PUSH    DS
  683.         PUSH    CS
  684.         POP    DS
  685.         LODSB
  686.         POP    DS
  687.         CMP    AL,0
  688.         JE    RPL_DONE
  689.         PUSH    SI
  690.         CALL    INSERT_KEY
  691.         POP    SI
  692.         JMP    SHORT RPL_LOOP
  693. RPL_DONE:
  694.         POP    AX
  695.         MOV    INSERT_MODE,AL
  696.         RET
  697.  
  698. REPLACE    ENDP
  699. ;-----------------------------------------------------------------------
  700. ; This moves the cursor to the top of the file.
  701. ;-----------------------------------------------------------------------
  702. TOP        PROC    NEAR
  703.         XOR    AX,AX        ;Get a zero into AX
  704.         MOV    CURSOR,AX    ;Cursor to start of file
  705.         MOV    TOP_OF_SCREEN,AX
  706.         MOV    LEFT_MARGIN,AL    ;Move to far left margin
  707.         MOV    DIRTY_BITS,1    ;Redraw the screen
  708.         MOV    CUR_POSN,AX    ;Home the cursor
  709.         MOV    SAVE_COLUMN,AL    ;Save the cursor column
  710.         RET
  711. TOP        ENDP
  712.  
  713. ;-----------------------------------------------------------------------
  714. ; This moves the cursor to the bottom of the file
  715. ;-----------------------------------------------------------------------
  716. BOTTOM        PROC    NEAR
  717.         MOV    DH,ROWS        ;Get screen size
  718.         MOV    SI,LAST_CHAR    ;Point to last character
  719.         DEC    SI
  720.         MOV    LEFT_MARGIN,0    ;Set window to start of line
  721.         CALL    LOCATE        ;Adjust the screen position
  722.         CALL    HOME        ;Move cursor to start of line
  723.         MOV    DIRTY_BITS,1    ;This will redraw the screen
  724.         RET
  725. BOTTOM        ENDP
  726.  
  727. ;-----------------------------------------------------------------------
  728. ; This subroutine is called to reformat remainder of para or selection
  729. ;-----------------------------------------------------------------------
  730. REFORMAT    PROC    NEAR
  731.         MOV    AL,WRAP_FLAG
  732.         PUSH    AX
  733.         MOV    WRAP_FLAG,0FFH    ;Wrap flag temporaily on
  734.         CMP    MARK_MODE,0    ;is wrap mode on?
  735.         JE    JOIN_NEXT
  736.         MOV    SI,MARK_START    ;start at marked text
  737.         MOV    CURSOR,SI
  738. JOIN_NEXT:
  739.         CALL    JOIN        ;join this line with the next
  740.         CMP    MARK_MODE,0
  741.         JE    REFORMAT_END    ;exit if mark mode off
  742.         CALL    FIND_NEXT_PARA
  743.         CMP    SI,MARK_END    ;end of selection?
  744.         JAE    REFORMAT_SELECT_END    ;then exit
  745.         MOV    CURSOR,SI
  746.         JMP    SHORT JOIN_NEXT    ;Next para found
  747. REFORMAT_SELECT_END:
  748.         MOV    SI,MARK_START
  749.         MOV    DH,3        ;Position on line 3
  750.         CALL    LOCATE
  751.         CALL    MARK        ;turn off mark mode
  752. REFORMAT_END:
  753.         POP    AX
  754.         MOV    WRAP_FLAG,AL
  755.         RET
  756. REFORMAT    ENDP
  757. ;-----------------------------------------------------------------------
  758. ; This deletes from the cursor position to the end of line.
  759. ;-----------------------------------------------------------------------
  760. DEL_EOL        PROC    NEAR
  761.         MOV    CX,CUR_POSN
  762.         OR    CL,CL        ;At first column?
  763.         JZ    DEL_L        ;If yes, then do line delete function
  764.         MOV    LINE_FLAG,0
  765.         PUSH    CURSOR        ;Save starting cursor location
  766.         CALL    ENDD        ;Move the the end of line
  767.         POP    SI        ;Get back starting cursor
  768.         MOV    CX,CURSOR    ;Offset of the end of line
  769.         MOV    CURSOR,SI    ;Restore starting cursor
  770.         JMP    DEL_END        ;Delete characters to end
  771. DEL_EOL        ENDP
  772.  
  773.  
  774. ;-----------------------------------------------------------------------
  775. ; This deletes a line, placing it in the line buffer.
  776. ;-----------------------------------------------------------------------
  777. DEL_L        PROC    NEAR
  778.         MOV    LINE_FLAG,1
  779.         CALL    FIND_START    ;Find start of this line
  780.         MOV    CURSOR,SI    ;This will be the new cursor
  781.         PUSH    SI        ;Save the cursor position
  782.         CALL    FIND_NEXT    ;Find the next line
  783.         MOV    CX,SI        ;CX will hold line length
  784.         POP    SI        ;Get back new cursor location
  785. DEL_END:
  786.         SUB    CX,SI        ;Number of bytes on line
  787.         OR    CH,CH        ;Is line too long to fit
  788.         JZ    NOT_TOO_LONG
  789.         MOV    CX,100H        ;Only save 256 characters
  790. NOT_TOO_LONG:
  791.         MOV    LINE_LENGTH,CX    ;Store length of deleted line
  792.         JCXZ    NO_DEL_L
  793.         MOV    DI,OFFSET LINE_BUFFER ;Buffer for deleted line
  794.  
  795.         PUSH    CX
  796.         PUSH    ES
  797.         PUSH    CS
  798.         POP    ES        ;Line buffer is in CSEG
  799.         REP    MOVSB        ;Put deleted line in buffer
  800.         POP    ES        ;Get back file segment
  801.         POP    AX
  802.  
  803.         MOV    CX,LAST_CHAR    ;Get the file size
  804.         SUB    LAST_CHAR,AX    ;Subtract the deleted line
  805.         MOV    SI,CURSOR    ;Get new cursor location
  806.         MOV    DI,SI
  807.         ADD    SI,AX        ;SI points to end of file
  808.         SUB    CX,SI        ;Length of remaining file
  809.         JCXZ    NO_DEL_L
  810.         REP    MOVSB        ;Shift remainder of file up
  811. NO_DEL_L:
  812.         MOV    DX,CUR_POSN    ;Get cursor row/column
  813.         MOV    SI,CURSOR    ;Get cursor offset
  814.         CALL    LOCATE        ;Adjust the screen position
  815.         MOV    DIRTY_BITS,1    ;Redraw the screen
  816.         RET
  817. DEL_L        ENDP
  818.  
  819. ;-----------------------------------------------------------------------
  820. ; This undeletes a line by copying it from the line buffer into the file
  821. ;-----------------------------------------------------------------------
  822. UDEL_L        PROC    NEAR
  823.         CMP    LINE_FLAG,0    ;Is this an end of line only?
  824.         JE    UDEL_EOL    ;If yes, don't home the cursor
  825.         CALL    HOME        ;Move cursor to home
  826. UDEL_EOL:
  827.         MOV    AX,LINE_LENGTH    ;Length of deleted line
  828.         MOV    SI,OFFSET LINE_BUFFER
  829.         JMP    INSERT_STRING
  830. UDEL_L        ENDP
  831.  
  832. ;-----------------------------------------------------------------------
  833. ; These routines move the cursor left and right.
  834. ;-----------------------------------------------------------------------
  835. LEFT        PROC    NEAR
  836.         CMP    CURSOR,0    ;At start of file?
  837.         JZ    LR_NO_CHANGE    ;Then can't move left
  838.         MOV    DX,CUR_POSN
  839.         OR    DL,DL        ;At first column?
  840.         JZ    MOVE_UP        ;If yes, then move up one
  841.         DEC    CURSOR        ;Shift the cursor offset
  842. LR_RETURN:
  843.         CALL    CURSOR_COL    ;Compute column for cursor
  844.         MOV    SAVE_COLUMN,DL    ;Save the cursor column
  845. LR_NO_CHANGE:
  846.         MOV    UNDO_LENGTH,0
  847.         RET
  848. MOVE_UP:
  849.         CALL    UP        ;Move up to next row
  850.         JMP    SHORT ENDD    ;And move to end of line
  851. LEFT        ENDP
  852.  
  853. RIGHT        PROC    NEAR
  854.         MOV    SI,CURSOR
  855.         CMP    SI,LAST_CHAR    ;At end of file?
  856.         JE    LR_NO_CHANGE    ;If yes, then can't move
  857.         CMP    BYTE PTR [SI],CR;If CR
  858.         JNE    INC_RIGHT    ;If yes, then test LF
  859.         INC    SI
  860.         CMP    SI,LAST_CHAR    ;At end of file?
  861.         DEC    SI
  862.         JE    INC_RIGHT    ;If yes, then increment
  863.         CMP    BYTE PTR [SI+1],LF;If LF
  864.         JE    NEXT_LINE    ;If yes, then move to next line
  865. INC_RIGHT:
  866.         INC    CURSOR        ;Advance the cursor
  867.         JMP    LR_RETURN
  868. NEXT_LINE:
  869.         CALL    HOME        ;Move to start of line
  870.         JMP    DOWN        ;And move down one row
  871. RIGHT        ENDP
  872.  
  873. ;-----------------------------------------------------------------------
  874. ; This moves the cursor to the start of the current line.
  875. ;-----------------------------------------------------------------------
  876. HOME        PROC    NEAR
  877.         CALL    FIND_START    ;Find start of line
  878.         MOV    CURSOR,SI    ;Save the new cursor
  879.         MOV    SAVE_COLUMN,0    ;Save the cursor column
  880.         MOV    BYTE PTR CUR_POSN,0 ;Store column number
  881.         RET
  882. HOME        ENDP
  883.  
  884. ;-----------------------------------------------------------------------
  885. ; This moves the cursor to the end of the current line
  886. ;-----------------------------------------------------------------------
  887. ENDD        PROC    NEAR
  888.         MOV    SI,CURSOR
  889.         CALL    FIND_EOL    ;Find end of this line
  890.         MOV    CURSOR,SI    ;Store the new cursor
  891.         CALL    CURSOR_COL    ;Compute the correct column
  892.         MOV    SAVE_COLUMN,DL    ;Save the cursor column
  893.         RET
  894. ENDD        ENDP
  895.  
  896. ;-----------------------------------------------------------------------
  897. ; This moves the cursor up one row.  If the cursor is at the first row,
  898. ; the screen is scrolled down.
  899. ;-----------------------------------------------------------------------
  900. UP        PROC    NEAR
  901.         MOV    UNDO_LENGTH,0
  902.         MOV    DX,CUR_POSN
  903.         MOV    SI,CURSOR
  904.         OR    DH,DH        ;At top row already?
  905.         JZ    SCREEN_DN    ;If yes, then scroll down
  906.         DEC    DH        ;Move cursor up one row
  907.         CALL    FIND_CR        ;Find the beginning of this row
  908.         MOV    CURSOR,SI
  909.         CALL    FIND_START    ;Find start of this row
  910.         MOV    CURSOR,SI
  911.         CALL    SHIFT_RIGHT    ;Skip over to current column
  912. AT_TOP:
  913.         RET
  914. SCREEN_DN:
  915.         MOV    SI,TOP_OF_SCREEN
  916.         OR    SI,SI        ;At start of file?
  917.         JZ    AT_TOP        ;If at top, then do nothing
  918.         CALL    FIND_PREVIOUS    ;Find the preceeding line
  919.         MOV    TOP_OF_SCREEN,SI;Save new top of screen
  920.         MOV    SI,CURSOR
  921.         CALL    FIND_PREVIOUS    ;Find the preceeding line
  922.         MOV    CURSOR,SI    ;This is the new cursor
  923. SHIFT_RET:
  924.         MOV    DIRTY_BITS,1    ;Need to redraw screen
  925.         MOV    SI,CURSOR
  926.         MOV    DX,CUR_POSN
  927.         JMP    SHIFT_RIGHT    ;Move cursor to current column
  928. UP        ENDP
  929.  
  930. ;-----------------------------------------------------------------------
  931. ; This moves the cursor down one row.  When the last row is reached,
  932. ; the screen is shifted up one row.
  933. ;-----------------------------------------------------------------------
  934. DOWN        PROC    NEAR
  935.         MOV    UNDO_LENGTH,0
  936.         MOV    DX,CUR_POSN
  937.         CMP    DH,ROWS        ;At bottom row already?
  938.         MOV    SI,CURSOR    ;Get position in file
  939.         JE    SCREEN_UP    ;If at bottom, then scroll up
  940.         CALL    FIND_NEXT    ;Find the start of next line
  941.         JC    DOWN_RET    ;If no more lines, then return
  942.         MOV    CURSOR,SI
  943.         INC    DH        ;Advance cursor to next row
  944.         CALL    SHIFT_RIGHT    ;Move cursor to current column
  945. DOWN_RET:
  946.         RET
  947. SCREEN_UP:
  948.         CMP    SI,LAST_CHAR    ;Get cursor offset
  949.         JE    DOWN_RET
  950.         CALL    FIND_START    ;Find the start of this line
  951.         MOV    CURSOR,SI    ;This is the new cursor
  952.         CALL    FIND_NEXT    ;Find the offset of next line
  953.         JC    SHIFT_RET    ;If no more lines then return
  954.         MOV    CURSOR,SI    ;This is the new cursor
  955.         MOV    SI,TOP_OF_SCREEN;Get the start of the top row
  956.         CALL    FIND_NEXT    ;And find the next line
  957.         MOV    TOP_OF_SCREEN,SI;Store the new top of screen
  958.         JMP    SHIFT_RET
  959. DOWN        ENDP
  960.  
  961. ;-----------------------------------------------------------------------
  962. ; These two routines move the screen one page at a time by calling the
  963. ; UP and DOWN procedures.
  964. ;-----------------------------------------------------------------------
  965. PGDN        PROC    NEAR
  966.         MOV    PAGE_PROC,OFFSET DOWN
  967. PAGE_UP_DN:
  968.         MOV    CL,ROWS        ;Get length of the screen
  969.         SUB    CL,5        ;Don't page a full screen
  970.         XOR    CH,CH        ;Make it a word
  971. PAGE_LOOP:
  972.         PUSH    CX
  973.         CALL    PAGE_PROC    ;Move the cursor down
  974.         POP    CX
  975.         LOOP    PAGE_LOOP    ;Loop for one page length
  976.         RET
  977. PGDN        ENDP
  978.  
  979. PGUP        PROC    NEAR
  980.         MOV    PAGE_PROC,OFFSET UP
  981.         JMP    PAGE_UP_DN
  982. PGUP        ENDP
  983.  
  984. ;-----------------------------------------------------------------------
  985. ; This toggles the insert/overstrike mode.
  986. ;-----------------------------------------------------------------------
  987. INSERT        PROC    NEAR
  988.         NOT    INSERT_MODE    ;Toggle the switch
  989.         JMP    REDO_PROMPT    ;Redraw the insert status
  990. INSERT        ENDP
  991.  
  992. ;-----------------------------------------------------------------------
  993. ; This deletes the character at the cursor by shifting the remaining 
  994. ; characters forward.
  995. ;-----------------------------------------------------------------------
  996. DEL_CHAR    PROC    NEAR
  997.         MOV    CX,LAST_CHAR
  998.         MOV    SI,CURSOR
  999.         MOV    DI,SI
  1000.         CMP    SI,CX        ;Are we at end of file?
  1001.         JAE    NO_DEL        ;If yes, then don't delete
  1002.         LODSB
  1003.         CALL    SAVE_CHAR    ;Save it for UNDO function
  1004.         CMP    SI,LAST_CHAR    ;at EOF?
  1005.         JNB    MOVE_DOWN
  1006.         CMP    AL,CR        ;Is it a CR?
  1007.         JNE    MOVE_DOWN
  1008.         LODSB
  1009.         CMP    AL,LF        ;Is it a LF?
  1010.         JE    DEL_LF
  1011.         DEC    SI        ;step back
  1012.         JMP    SHORT MOVE_DOWN
  1013. DEL_LF:
  1014.         CALL    SAVE_CHAR    ;Save it for UNDO function
  1015.         CMP    WRAP_FLAG,0    ;word wrap on?
  1016.         JE    CR_LF_DEL    ;if not then skip
  1017.         MOV    AX,[SI]
  1018.         CMP    AX,LF*256 +CR; Followed by a blank line?
  1019.         JE    CR_LF_DEL
  1020.         DEC    SI        ;step back passed EOL
  1021.         DEC    SI
  1022.         CALL    JOIN
  1023.         JMP    SHORT EOL_DEL
  1024. MOVE_DOWN:
  1025.         SUB    CX,SI        ;Calculate no. of chars to move
  1026.         MOV    AX,CX
  1027.         ADD    AX,DI
  1028.         MOV    LAST_CHAR,AX    ;Adjust file length
  1029.         REP    MOVSB        ;Move file down one notch
  1030.         OR    DIRTY_BITS,4    ;Current line is dirty
  1031. NO_DEL:
  1032.         RET
  1033. CR_LF_DEL:
  1034.         SUB    CX,SI        ;Calculate no. of chars to move
  1035.         MOV    AX,CX
  1036.         ADD    AX,DI
  1037.         MOV    LAST_CHAR,AX    ;Adjust file length
  1038.         REP    MOVSB        ;Move file down one notch
  1039. EOL_DEL:
  1040.         OR    DIRTY_BITS,2    ;bottom of screen is dirty
  1041.         MOV    DX,CUR_POSN
  1042.         MOV    SAVE_COLUMN,DL    ;Save the cursor column
  1043.         RET
  1044. DEL_CHAR    ENDP
  1045.  
  1046. ;-----------------------------------------------------------------------
  1047. ; This toggles the mark state and resets the paste buffer pointers.
  1048. ;-----------------------------------------------------------------------
  1049. MARK        PROC    NEAR
  1050.         XOR    AX,AX
  1051.         NOT    MARK_MODE    ;Toggle the mode flag
  1052.         CMP    MARK_MODE,AL    ;Turning mode ON?
  1053.         JNE    MARK_ON
  1054.         MOV    DIRTY_BITS,1    ;Need to redraw the screen
  1055.         MOV    MARK_START,0FFFFH
  1056.         JMP    SHORT MARK_RET
  1057. MARK_ON:
  1058.         MOV    AX,CURSOR    ;Get the cursor offset
  1059.         MOV    MARK_START,AX    ;Start of marked range
  1060. MARK_RET:
  1061.         MOV    MARK_END,  AX    ;End of marked range
  1062.         MOV    MARK_HOME, AX    ;Center of marked range
  1063.         RET
  1064. MARK        ENDP
  1065.  
  1066. ;-----------------------------------------------------------------------
  1067. ; This removes the marked text and places it in the paste buffer
  1068. ;-----------------------------------------------------------------------
  1069. CUT        PROC    NEAR
  1070.         CMP    MARK_MODE,0    ;Is the mark mode on?
  1071.         JE    NO_MARK        ;If not, then do nothing
  1072.         MOV    CX,MARK_END    ;Get end of mark region
  1073.         MOV    SI,MARK_START    ;Get start of mark region
  1074.         SUB    CX,SI        ;Number of bytes selected
  1075.         MOV    PASTE_SIZE,CX
  1076.         JCXZ    NO_MARK
  1077.         XOR    DI,DI        ;Point to paste bufferf
  1078.  
  1079.         PUSH    CX
  1080.         PUSH    ES
  1081.         MOV    ES,PASTE_SEG    ;Get the paste segment
  1082.         REP    MOVSB        ;Put deleted text in buffer
  1083.         POP    ES
  1084.         POP    AX
  1085.  
  1086.         MOV    CX,LAST_CHAR
  1087.         SUB    LAST_CHAR,AX    ;Shorten the file this much
  1088.         MOV    DI,MARK_START
  1089.         MOV    SI,MARK_END
  1090.         SUB    CX,SI
  1091.         JCXZ    NO_DELETE
  1092.         REP    MOVSB        ;Shorten the file
  1093. NO_DELETE:
  1094.         MOV    DX,CUR_POSN
  1095.         MOV    SI,MARK_START
  1096.         CALL    LOCATE        ;Adjust the screen position
  1097.         CALL    MARK        ;This turns off select
  1098. NO_MARK:
  1099.         RET
  1100. CUT        ENDP
  1101.  
  1102. ;-----------------------------------------------------------------------
  1103. ; This copies the paste buffer into the file at the cursor location
  1104. ;-----------------------------------------------------------------------
  1105. PASTE        PROC    NEAR
  1106.         MOV    AX,PASTE_SIZE    ;Number of characters in buffer
  1107.         OR    AX,AX        ;Any there?
  1108.         JZ    NO_PASTE    ;If not, nothing to paste
  1109.         PUSH    AX
  1110.         CALL    OPEN_SPACE    ;Make room for new characters
  1111.         POP    CX
  1112.         JC    NO_PASTE    ;If no room, just exit
  1113.         XOR    SI,SI        ;Point to paste buffer
  1114.         MOV    DI,CURSOR    ;destination is cursor position
  1115.         PUSH    DS
  1116.         MOV    DS,PASTE_SEG    ;Segment of paste buffer
  1117.         REP    MOVSB        ;Copy in the new characters
  1118.         POP    DS
  1119.         MOV    CURSOR,DI    ;Cursor moved to end of insert
  1120. PASTE_END:
  1121.         MOV    SI,CURSOR
  1122.         MOV    DX,CUR_POSN    ;Get current cursor row
  1123.         CALL    LOCATE        ;Adjust the screen position
  1124.         MOV    DIRTY_BITS,1    ;Redraw the screen
  1125. NO_PASTE:
  1126.         RET
  1127. PASTE        ENDP
  1128. ;-----------------------------------------------------------------------
  1129. ; This copies the paste buffer into the file at the cursor location with
  1130. ; a quote character at start of each line
  1131. ;-----------------------------------------------------------------------
  1132. QUOTE        PROC    NEAR
  1133.         MOV    AX,PASTE_SIZE    ;Number of characters in buffer
  1134.         OR    AX,AX        ;Any there?
  1135.         JZ    NO_PASTE    ;If not, nothing to paste
  1136.         XOR    SI,SI        ;top of buffer
  1137. PASTE_LOOP:
  1138.         PUSH    SI
  1139.         PUSH    DS
  1140.         PUSH    ES
  1141.         MOV    DS,PASTE_SEG    ;change to paste segment
  1142.         MOV    ES,PASTE_SEG
  1143.         PUSH    LAST_CHAR
  1144.         MOV    AX,PASTE_SIZE
  1145.         MOV    LAST_CHAR,AX
  1146.         CALL    FIND_NEXT    ;find the start of the next line
  1147.         POP    LAST_CHAR
  1148.         POP    ES
  1149.         POP    DS        ;restore file segment
  1150.         MOV    AX,SI
  1151.         POP    SI
  1152.         SUB    AX,SI        ;No of chars in line
  1153.         JZ    PASTE_END    ;no more to move
  1154.         PUSH    AX
  1155.         INC    AX        ;plus space for quote character
  1156.         PUSH    SI
  1157.         CALL    OPEN_SPACE    ;make room
  1158.         POP    SI
  1159.         POP    CX
  1160.         JC    PASTE_END    ;exit if no more room
  1161.         PUSH    DS
  1162.         MOV    DS,PASTE_SEG
  1163.         MOV    DI,CURSOR
  1164.         MOV    AL,QUOTE_CHAR    ;First insert quote character
  1165.         STOSB
  1166.         REP    MOVSB        ;then insert next line
  1167.         POP    DS
  1168.         MOV    CURSOR,DI    ;set cursor to after insertion
  1169.         JMP    SHORT PASTE_LOOP
  1170. QUOTE        ENDP
  1171.  
  1172. ;-----------------------------------------------------------------------
  1173. ; This prints the marked text.  If printer fails, it is canceled.
  1174. ;-----------------------------------------------------------------------
  1175. PRINT        PROC    NEAR
  1176.         CMP    MARK_MODE,0    ;Is mark mode on?
  1177.         JE    PRINT_ALL    ;If not, print whole file
  1178.         MOV    CX,MARK_END    ;End of marked region
  1179.         MOV    SI,MARK_START    ;Start of marked region
  1180.         SUB    CX,SI        ;Number of bytes selected
  1181.         JCXZ    PRINT_DONE    ;If nothing to print, return
  1182.         JMP    PRINT_TEST
  1183. PRINT_ALL:
  1184.         MOV    CX,LAST_CHAR    ;End of File
  1185.         JCXZ    PRINT_DONE    ;If nothing to print, return
  1186.         PUSH    CX
  1187.         MOV    SI,OFFSET PRINT_CONFIRM
  1188.         CALL    ASK_STRING    ;get confirmation
  1189.         POP    CX
  1190.         JNE    PRINT_DONE    ;Exit if no
  1191.         XOR    SI,SI        ;Start of File
  1192. PRINT_TEST:
  1193.         MOV    AH,2
  1194.         XOR    DX,DX        ;Select printer 0
  1195.         INT    17H        ;Get printer status
  1196.         TEST    AH,10000000B    ;Is busy bit set?
  1197.         JZ    PRINT_DONE
  1198.         TEST    AH,00100000B    ;Is printer out of paper?
  1199.         JNZ    PRINT_DONE
  1200. PRINT_LOOP:
  1201.         LODSB
  1202.         XOR    AH,AH
  1203.         INT    17H        ;Print the character
  1204.         ROR    AH,1        ;Check time out bit
  1205.         JC    PRINT_DONE    ;If set, quit printing
  1206.         LOOP    PRINT_LOOP
  1207.         MOV    AL,CR
  1208.         XOR    AH,0
  1209.         INT    17H        ;Finish with a CR
  1210. PRINT_DONE:
  1211.         CMP    MARK_MODE,0    ;Is mark mode on?
  1212.         JE    PRINT_FF    ;If not then send a FF
  1213.         CALL    MARK        ;Turn off the mark state
  1214. PRINT_RET:
  1215.         RET
  1216. PRINT_FF:
  1217.         MOV    AL,FF        ;Print a FF
  1218.         XOR    AH,AH
  1219.         INT    17H
  1220.         RET
  1221. PRINT        ENDP
  1222. ;-----------------------------------------------------------------------
  1223. ; This subroutine reads a named file into the paste buffer and then pastes
  1224. ; the contents of the paste buffer into the file being edited at the current
  1225. ; cursor position.
  1226. ;-----------------------------------------------------------------------
  1227.  
  1228. INSERT_FILE    PROC    NEAR
  1229.         ASSUME    DS:CSEG
  1230.         PUSH    DS
  1231.         PUSH    CS
  1232.         POP    DS
  1233.         MOV    AX,PASTE_SIZE    ;Check for empty paste buffer
  1234.         OR    AX,AX
  1235.         JZ    GET_IN_FILENAME    ;Empty, then get on with it
  1236.         MOV    SI, OFFSET DEL_PASTE_MESS
  1237.         CALL    ASK_STRING    ;Ask if OK to overwrite
  1238.         JNE    IN_ERROR_EXIT    ;If no then do nothing
  1239. GET_IN_FILENAME:
  1240.         MOV    DI,OFFSET IN_FILE_MESS    ;Input prompt
  1241.         MOV    SI,OFFSET IN_FILENAME    ;Buffer to receive filename
  1242.         MOV    CX,BUFF_SIZE
  1243.         CALL    READ_STRING        ;prompt for filename
  1244.         MOV    AL,IN_FILENAME
  1245.         OR    AL,AL        ;Is it zero:
  1246.         JZ    IN_ERROR_EXIT    ;Empty string - do nothing
  1247.         MOV    SI,OFFSET IN_FILENAME
  1248. IN_DEL_SPACES:                ;Remove leading spaces
  1249.         LODSB            ;Get next character
  1250.         CMP    AL," "        ;is it a space?
  1251.         JNE    IN_READ_FILE    ;Non-space found then filename found
  1252.         LOOP    IN_DEL_SPACES
  1253. IN_READ_FILE:
  1254.         DEC    SI        ;Point again to first letter
  1255.         MOV    DX,SI
  1256.         MOV    AX,3D00H    ;Command code to open file
  1257.         INT     21H
  1258.         JC    IN_BAD_FILE    ;Error exit
  1259.         PUSH    DS
  1260.         MOV    DS,PASTE_SEG    ;DS points to paste buffer
  1261.         XOR    DX,DX
  1262.         MOV    BX,AX        ;Put file handle into BX
  1263.         MOV    AH,3FH        ;Read Command
  1264.         MOV    CX,0FFFEH    ;Set maximum at just under 64K
  1265.         INT    21H
  1266.         POP    DS        ;Restore DS
  1267.         JC    IN_READ_ERROR    ;Error exit
  1268.         PUSH    BX
  1269.         MOV    PASTE_SIZE,AX    ;No. of bytes read in
  1270.         CMP    CX,AX        ;All of file read in?
  1271.         JNE    IN_PASTE
  1272.         MOV    SI,OFFSET TRUNCATE_MESS
  1273.         CALL    ERROR_MESG
  1274. IN_PASTE:
  1275.         POP    BX
  1276.         MOV    AH,3EH        ;Close the file
  1277.         INT    21H
  1278.         POP    DS
  1279.         ASSUME    DS:NOTHING
  1280.         CMP    QUOTE_FLAG,0    ;Need to quote file?
  1281.         JZ    PASTE_FILE
  1282.         CALL    QUOTE
  1283.         JMP    SHORT INSERT_COMPLETE
  1284. PASTE_FILE:
  1285.         CALL    PASTE        ;Insert read in file contents
  1286.         JMP    SHORT INSERT_COMPLETE
  1287. IN_READ_ERROR:
  1288.         MOV    SI,OFFSET IN_READ_ERR
  1289.         CALL    ERROR_MESG
  1290.         JMP    SHORT IN_ERROR_EXIT
  1291. IN_BAD_FILE:
  1292.         MOV    SI,OFFSET NO_FILE_MESS
  1293.         CALL    ERROR_MESG
  1294. IN_ERROR_EXIT:
  1295.         POP    DS
  1296. INSERT_COMPLETE:
  1297.         MOV    QUOTE_FLAG,0
  1298.         CALL    REDO_PROMPT
  1299.         RET        ;Exit        
  1300. INSERT_FILE    ENDP
  1301. ;-----------------------------------------------------------------------
  1302. ; This command restores any characters which have recently been deleted.
  1303. ;-----------------------------------------------------------------------
  1304. UNDO        PROC    NEAR
  1305.         XOR    AX,AX
  1306.         XCHG    AX,UNDO_LENGTH    ;Get buffer length
  1307.         MOV    SI,OFFSET UNDO_BUFFER
  1308.         JMP    INSERT_STRING
  1309. UNDO        ENDP
  1310.  
  1311. ;-----------------------------------------------------------------------
  1312. ; This inserts AX characters from CS:SI into the file.
  1313. ;-----------------------------------------------------------------------
  1314. INSERT_STRING    PROC    NEAR
  1315.         PUSH    SI        ;Save string buffer
  1316.         MOV    SI,CURSOR    ;Get cursor offset
  1317.         PUSH    AX        ;Save length of string
  1318.         PUSH    SI
  1319.         CALL    OPEN_SPACE    ;Make space to insert string
  1320.         POP    DI        ;Get back cursor position
  1321.         POP    CX        ;Get back string length
  1322.         POP    SI        ;Get back string buffer
  1323.         JC    NO_SPACE    ;If no space available, exit
  1324.  
  1325.         PUSH    DS
  1326.         PUSH    CS
  1327.         POP    DS
  1328.         ASSUME    DS:CSEG
  1329.         REP    MOVSB        ;Copy the characters in
  1330.         MOV    SI,CURSOR    ;Get the new cursor offset
  1331.         MOV    DX,CUR_POSN    ;Also get the current row
  1332.         MOV    DIRTY_BITS,1    ;And redraw the screen
  1333.         POP    DS
  1334.         ASSUME    DS:NOTHING
  1335.         CALL    LOCATE        ;Adjust the screen position
  1336. NO_SPACE:
  1337.         RET
  1338. INSERT_STRING    ENDP
  1339.  
  1340. ;-----------------------------------------------------------------------
  1341. ; This adds a character to the undo buffer.
  1342. ;-----------------------------------------------------------------------
  1343. SAVE_CHAR    PROC    NEAR
  1344.         MOV    BX,UNDO_LENGTH
  1345.         OR    BH,BH        ;Is buffer filled?
  1346.         JNZ    NO_SAVE
  1347.         INC    UNDO_LENGTH
  1348.         MOV    BYTE PTR CS:UNDO_BUFFER[BX],AL
  1349. NO_SAVE:
  1350.         RET
  1351. SAVE_CHAR    ENDP
  1352.  
  1353. ;-----------------------------------------------------------------------
  1354. ; This subroutine draws a double line across the screen AX = corner chars
  1355. ;------------------------------------------------------------------------
  1356. LINE_DRAW    PROC    NEAR
  1357.         XOR    DL,DL        ;And column 0
  1358.         PUSH    AX
  1359.         CALL    POSITION    ;Convert to screen offset
  1360.         POP    AX        ;AL contains left hand corner
  1361.         PUSH    AX
  1362.         CALL    WRITE_INVERSE
  1363.         MOV    CX,COLUMNS    ;screen width
  1364.         DEC    CX
  1365.         DEC    CX
  1366. DRAW_LOOP:
  1367.         MOV    AL,"═"        ;output line character
  1368.         CALL    WRITE_INVERSE
  1369.         LOOP    DRAW_LOOP
  1370.         POP    AX
  1371.         MOV    AL,AH
  1372.         CALL    WRITE_INVERSE
  1373.         RET
  1374. LINE_DRAW    ENDP
  1375. ;-----------------------------------------------------------------------
  1376. ; This Subrouting displays a HELP screen
  1377. ;-----------------------------------------------------------------------
  1378. HELP        PROC    NEAR
  1379.         PUSH    DS
  1380.         PUSH    CS
  1381.         POP    DS
  1382.         ASSUME    DS:CSEG
  1383.         MOV    DH,HELP_ROW        ;Put prompt at start of help
  1384.         MOV    AL,"╔"        ;Output top left hand corner
  1385.         MOV    AH,"╗"        ;output top right hand corner
  1386.         PUSH    DX
  1387.         CALL    LINE_DRAW
  1388.         POP    DX
  1389.         MOV    SI,OFFSET HELP_TEXT
  1390. LINE_LOOP:
  1391.         INC    DH        ;next row
  1392.         XOR    DL,DL        ;column 0
  1393.         PUSH    DX
  1394.         CALL    POSITION    ;goto start of next row
  1395.         MOV    AL,"║"        ;output vertical line
  1396.         CALL    WRITE_INVERSE
  1397.         POP    DX
  1398.         INC    DL
  1399.         PUSH    DX
  1400.         CALL    ERASE_EOL    ;clear reset of line
  1401.         POP    DX
  1402.         MOV    CX,HELP_COLS    ;Four columns on screen
  1403. HELP_LINE_LOOP:
  1404.         MOV    DI,HELP_COLS
  1405.         SUB    DI,CX        ;Form index for col start array
  1406.         MOV    DL,HELP_OFFSETS[DI]
  1407.         PUSH    CX
  1408.         PUSH    DX
  1409.         CALL    POSITION    ;goto column 4
  1410. HELP_TEXT_LOOP:
  1411.         LODSB            ;get first character of function name
  1412.         OR    AL,AL        ;zero is end of text
  1413.         JZ    END_HELP_TEXT
  1414.         CMP    AL,-1        ;Test for End of text
  1415.         JE    HELP_END
  1416.         CALL    WRITE_NORMAL
  1417.         JMP    SHORT HELP_TEXT_LOOP
  1418. END_HELP_TEXT:
  1419.         POP    DX
  1420.         POP    CX
  1421.         LOOP    HELP_LINE_LOOP
  1422.         MOV    DL,COLUMNSB
  1423.         DEC    DL
  1424.         PUSH    DX
  1425.         CALL    POSITION    ;goto last column
  1426.         MOV    AL,"║"        ;output vertical line
  1427.         CALL    WRITE_INVERSE
  1428.         POP    DX
  1429.         JMP    LINE_LOOP
  1430. HELP_END:
  1431.         POP    DX
  1432.         POP    CX
  1433.         MOV    DL,26        ;column 26
  1434.         MOV    SI,OFFSET CONTINUE_MESS
  1435.         PUSH    DX
  1436.         CALL    TTY_STRING
  1437.         POP    DX
  1438.         MOV    DL,COLUMNSB
  1439.         DEC    DL
  1440.         PUSH    DX
  1441.         CALL    POSITION    ;goto column 80
  1442.         MOV    AL,"║"        ;output vertical line
  1443.         CALL    WRITE_INVERSE
  1444.         POP    DX
  1445.         INC    DH        ;next row
  1446.         MOV    AL,"╚"        ;Output bottom left hand corner
  1447.         MOV    AH,"╝"        ;output bottom right hand corner
  1448.         CALL    LINE_DRAW
  1449.         MOV    AH,KEYREAD_CODE
  1450.         INT    16H        ;wait for key press
  1451.         POP    DS
  1452.         ASSUME    DS:NOTHING
  1453.         CALL    REDO_PROMPT
  1454.         MOV    DIRTY_BITS,1    ;redraw screen
  1455.         RET
  1456. HELP        ENDP
  1457. ;-----------------------------------------------------------------------
  1458. ; This prompts for a verify keystroke then exits without saving the file
  1459. ;-----------------------------------------------------------------------
  1460. ABORT        PROC    NEAR
  1461.         MOV    SI, OFFSET ABORT_MESS
  1462.         CALL    ASK_STRING    ;Prompt to confirm abort
  1463.         JE    FINISHED    ;If result is yes then exit
  1464.         RET            ;Otherwise continue
  1465. FINISHED:
  1466.         ASSUME    DS:CSEG
  1467.         PUSH    CS
  1468.         POP    DS
  1469.         MOV    DH,ROWS        ;Move to last row on screen
  1470.         XOR    DL,DL        ;And column zero
  1471.         CALL    SET_CURSOR
  1472.         INC    DH
  1473.         MOV    AL,SAVE_ATR        ;Get original screen attribute
  1474.         MOV    ORGATR,AL        ;Restore original screen attribute
  1475.         CALL    ERASE_EOL    ;Erase the last row
  1476.         MOV    DX,OFFSET COPYRIGHT
  1477.         MOV    AH,9
  1478.         INT    21H    ;Output copyright message
  1479. EXIT_TO_DOS:
  1480.         MOV    AX,4C00H
  1481.         INT    21H
  1482.  
  1483. ABORT        ENDP
  1484.  
  1485. ;-----------------------------------------------------------------------
  1486. ;sAVES FILE AND THEN EXITS IF ok
  1487. ;-----------------------------------------------------------------------
  1488. EXIT        PROC    NEAR
  1489. IFNDEF MAIL
  1490.         CALL    SAVE_FILE
  1491. ELSE
  1492.         CALL    TEST_FILENAME
  1493. ENDIF
  1494.         JC    FINISHED
  1495.         RET
  1496. EXIT        ENDP
  1497.  
  1498. ;-----------------------------------------------------------------------
  1499. ; This prompts for a filename then writes the file.  The original file
  1500. ; is renamed to filename.BAK.  If an invalid filename is entered, the 
  1501. ; speaker is beeped. Carry set if OK to exit
  1502. ;-----------------------------------------------------------------------
  1503. SAVE_FILE    PROC
  1504. IFDEF MAIL
  1505.         PUSH    DS
  1506.         PUSH    ES
  1507.         MOV    AX,CS
  1508.         MOV    DS,AX
  1509.         MOV    ES,AX
  1510.         MOV    SI,NAME_POINTER
  1511.         MOV    DI,OFFSET SAVE_FILENAME
  1512. SAVE_LOOP1:                ;Save current filename
  1513.         LODSB
  1514.         STOSB
  1515.         CMP    AL,0
  1516.         JE    SAVE_LOOP1_DONE
  1517.         JMP    SHORT SAVE_LOOP1
  1518. SAVE_LOOP1_DONE:
  1519.         POP    ES
  1520.         POP    DS
  1521.         CALL    SAVEAS
  1522.         PUSH    DS
  1523.         PUSH    ES
  1524.         MOV    AX,CS
  1525.         MOV    DS,AX
  1526.         MOV    ES,AX
  1527.         MOV    DI,NAME_POINTER
  1528.         MOV    SI,OFFSET SAVE_FILENAME
  1529. SAVE_LOOP2:                ;Restore current filename
  1530.         LODSB
  1531.         STOSB
  1532.         CMP    AL,0
  1533.         JE    SAVE_LOOP2_DONE
  1534.         JMP    SHORT SAVE_LOOP2
  1535. SAVE_LOOP2_DONE:
  1536.         POP    ES
  1537.         POP    DS
  1538.         RET
  1539.  
  1540. SAVEAS:
  1541. ENDIF
  1542.         ASSUME    DS:NOTHING
  1543.         MOV    DI,OFFSET SAVE_MESS
  1544.         MOV    SI,NAME_POINTER
  1545.         MOV    CX,81H+BUFF_SIZE
  1546.         SUB    CX,SI        ;buffer space available
  1547.         CALL    READ_STRING
  1548.         JC    TEST_FILENAME
  1549.         CALL    REDO_PROMPT
  1550.         CLC
  1551.         RET
  1552. TEST_FILENAME:
  1553.         PUSH    DS
  1554.         PUSH    ES
  1555.         MOV    AX,CS
  1556.         MOV    DS,AX
  1557.         MOV    ES,AX
  1558.         ASSUME    DS:CSEG, ES:CSEG
  1559.         MOV    DX,NAME_POINTER    ;Point to the filename
  1560.         MOV    AX,4300H    ;Get the files attribute
  1561.         INT    21H
  1562.         JNC    NAME_OK        ;If no error, filename is OK
  1563.         CMP    AX,3        ;Was it path not found error?
  1564.         JE    BAD_NAME    ;If yes, filename was bad
  1565. NAME_OK:
  1566.         MOV    SI,OFFSET DOT_$$$    ;Point to the ".$$$"
  1567.         MOV    DI,OFFSET NAME_DOT_$$$
  1568.         CALL    CHG_EXTENSION        ;Add the new extension
  1569.  
  1570.         MOV    DX,OFFSET NAME_DOT_$$$    ;Point to the temp filename
  1571.         MOV    AH,3CH            ;Function to create file
  1572.         MOV    CX,0020H        ;Attribute for new file
  1573.         INT    21H            ;Try to create the file
  1574.         JNC    NAME_WAS_OK        ;Continue if name was OK
  1575. BAD_NAME:
  1576.         MOV    AX,0E07H    ;Write a bell character
  1577.         INT    10H        ;BIOS tty service
  1578.         CLC
  1579.         JMP    SAVE_ERROR_EXIT    ;Get another letter
  1580. WRITE_ERROR:
  1581.         MOV    AH,3EH        ;Close the file
  1582.         INT    21H
  1583.         JMP    BAD_NAME    ;Filename must be bad
  1584. NAME_WAS_OK:
  1585.         XOR    DX,DX        ;This is the file buffer
  1586.         MOV    CX,LAST_CHAR    ;Number of chars in file
  1587.         MOV    DI,CX
  1588.         MOV    BX,AX        ;This is the handle
  1589.         JCXZ    EXIT_ZERO    ;Empty File?
  1590.         MOV    AH,40H        ;Write to the file
  1591.         POP    DS        ;Recover buffer segment
  1592.         INT    21H        ;Write the buffer contents
  1593.         PUSH    DS
  1594.         JC    WRITE_ERROR    ;Exit on a write error
  1595.         CMP    AX,CX        ;Was entire file written?
  1596.         JNE    WRITE_ERROR    ;If not, exit
  1597. EXIT_ZERO:
  1598.         PUSH    CS
  1599.         POP    DS        ;Get the code segment
  1600.         MOV    AH,3EH
  1601.         INT    21H            ;Close the temp file
  1602.         MOV    SI,OFFSET DOT_BAK    ;Point to the ".BAK"
  1603.         MOV    DI,OFFSET NAME_DOT_BAK
  1604.         CALL    CHG_EXTENSION        ;Make the backup filename
  1605.  
  1606.         MOV    DX,OFFSET NAME_DOT_BAK    ;Point to the backup name
  1607.         MOV    AH,41H
  1608.         INT    21H            ;Delete existing backup file
  1609.         MOV    DI,OFFSET NAME_DOT_BAK
  1610.         MOV    DX,NAME_POINTER
  1611.         MOV    AH,56H
  1612.         INT    21H
  1613.  
  1614.         MOV    DI,NAME_POINTER    ;Point to new filename
  1615.         MOV    DX,OFFSET NAME_DOT_$$$ ;Point to temporary file
  1616.         MOV    AH,56H        ;Rename temp to new file
  1617.         INT    21H        ;DOS function to rename
  1618.         STC
  1619. SAVE_ERROR_EXIT:
  1620.         POP    ES        ;Restore the stack
  1621.         POP    DS
  1622.         RET
  1623. SAVE_FILE    ENDP
  1624.  
  1625. ;----------------------------------------------------------------------
  1626. ; This subroutine reads a string of up to CX (<=BUFF_SIZE) characters from the keyboard
  1627. ; DI points to prompt, SI to buffer
  1628. ;----------------------------------------------------------------------
  1629. READ_STRING    PROC    NEAR
  1630.         PUSH    DS
  1631.         PUSH    ES
  1632.         MOV    AX,CS
  1633.         MOV    DS,AX
  1634.         MOV    ES,AX
  1635.         ASSUME    DS:CSEG, ES:CSEG
  1636.         MOV    BX,SI        ;save start of buffer
  1637.         PUSH    DI        ;save prompt pointer
  1638.         PUSH    CX
  1639.         MOV    DI,OFFSET SAVE_NAME_BUFF
  1640.         REP    MOVSB        ;save current buffer contents
  1641.         POP    CX
  1642.         POP    SI        ;SI is now prompt pointer
  1643. NEXT_LETTER:
  1644.         MOV    DH,ROWS
  1645.         INC    DH        ;Last row on the screen
  1646.         XOR    DL,DL        ;First column
  1647.         PUSH    BX
  1648.         PUSH    CX
  1649.         PUSH    SI
  1650.         PUSH    BX
  1651.         CALL    TTY_STRING    ;Display a prompt
  1652.         POP    SI        ;get address of input buffer
  1653.         CALL    TTY_STRING    ;Display the filename
  1654.         DEC    SI
  1655.         MOV    DI,SI        ;DI points to EOB
  1656.         POP    SI
  1657.         POP    CX
  1658.         POP    BX
  1659.         MOV    AH,KEYREAD_CODE    ;Read the next key
  1660.         INT    16H
  1661.         OR    AL,AL        ;Is it a real character?
  1662.         JZ    SPECIAL_KEY
  1663.         CMP    AL,224        ;Extended Key?
  1664.         JE    SPECIAL_KEY
  1665.         CMP    AL,ESC        ;Is it escape?
  1666.         JNE    NOT_ESCAPE
  1667.         MOV    DI,BX
  1668.         MOV    SI,OFFSET SAVE_NAME_BUFF
  1669.         REP    MOVSB        ;restore original contents
  1670.         CLC
  1671.         JMP    SHORT READS_END    ;Then exit
  1672. SPECIAL_KEY:
  1673.         CMP    AH,DEL        ;Is it a Delete char?
  1674.         JNE    NEXT_LETTER    ;otherwise ignore
  1675.         MOV    BYTE PTR [BX],0    ;Clear buffer
  1676.         JMP    SHORT NEXT_LETTER
  1677. NOT_ESCAPE:
  1678.         CMP    AL,CR        ;Is it CR?
  1679.         JE    GOT_NAME
  1680.         CMP    AL,BS        ;Is it a backspace?
  1681.         JNE    NORMAL_LETTER
  1682.         CMP    BX,DI        ;At first letter?
  1683.         JNB    NEXT_LETTER    ;If yes, dont erase it
  1684.         DEC    DI
  1685.         MOV    BYTE PTR [DI],0
  1686.         JMP    SHORT NEXT_LETTER
  1687. NORMAL_LETTER:
  1688.         MOV    DX,DI
  1689.         SUB    DX,BX
  1690.         CMP    DX,CX        ;Too many letters?
  1691.         JA    NEXT_LETTER    ;If yes, ignore them
  1692.         XOR    AH,AH
  1693.         STOSW            ;Store the new letter
  1694.         DEC    DI
  1695.         JMP    NEXT_LETTER    ;Read another keystroke
  1696. GOT_NAME:
  1697.         STC
  1698. READS_END:
  1699.         PUSHF
  1700.         CALL    REDO_PROMPT
  1701.         POPF
  1702.         POP    ES
  1703.         POP    DS
  1704.         RET
  1705. READ_STRING    ENDP
  1706. ;-----------------------------------------------------------------------
  1707. ; This subroutine displays a character by writing directly
  1708. ; to the screen buffer.  To avoid screen noise (snow) on the color
  1709. ; card, the horizontal retrace has to be monitored.
  1710. ;-----------------------------------------------------------------------
  1711. WRITE_INVERSE    PROC    NEAR
  1712.         ASSUME    DS:FILE_SEG, ES:FILE_SEG
  1713.         MOV    BH,INVATR
  1714.         JMP    SHORT WRITE_SCREEN
  1715. WRITE_NORMAL:
  1716.         MOV    BH,ORGATR    ;Attribute for normal video
  1717.         JMP    SHORT WRITE_SCREEN
  1718. WRITE_FIND:
  1719.         MOV    BH,SRCHATR    ;Attribute for find string
  1720. WRITE_SCREEN:
  1721.         MOV    BL,AL        ;Save the character
  1722.         PUSH    ES
  1723.         MOV    DX,STATUS_REG     ;Retrieve status register
  1724.         MOV    ES,VIDEO_SEG    ;Get segment of video buffer
  1725. HWAIT:
  1726.         IN    AL,DX        ;Get video status
  1727.         ROR    AL,1        ;Look at horizontal retrace
  1728.         JNC    HWAIT        ;Wait for retrace
  1729. WRITE_IT:
  1730.         MOV    AX,BX        ;Get the character/attribute
  1731.         STOSW            ;Write the character
  1732.         POP    ES
  1733.         RET
  1734. WRITE_INVERSE    ENDP
  1735.  
  1736. ;-----------------------------------------------------------------------
  1737. ; This moves the cursor to the row/column in DX.
  1738. ;-----------------------------------------------------------------------
  1739. SET_CURSOR    PROC    NEAR
  1740.         XOR    BH,BH        ;Were using page zero
  1741.         MOV    AH,2        ;BIOS set cursor function
  1742.         INT    10H
  1743.         RET
  1744. SET_CURSOR    ENDP
  1745.  
  1746. ;-----------------------------------------------------------------------
  1747. ; This computes the video buffer offset for the row/column in DX
  1748. ;----------------------------------------------------------------------
  1749. POSITION    PROC    NEAR
  1750.         MOV    AX,COLUMNS    ;Take columns per row
  1751.         MUL    DH        ;Times row number
  1752.         XOR    DH,DH
  1753.         ADD    AX,DX        ;Add in the column number
  1754.         SHL    AX,1        ;Times 2 for offset
  1755.         MOV    DI,AX        ;Return result in DI
  1756.         RET
  1757. POSITION    ENDP
  1758.  
  1759. ;-----------------------------------------------------------------------
  1760. ; This erases from the location in DX to the right edge of the screen
  1761. ;-----------------------------------------------------------------------
  1762. ERASE_EOL    PROC    NEAR
  1763.         PUSH    DX
  1764.         CALL    POSITION    ;Find screen offset
  1765.         MOV    CX,COLUMNS    ;Get screen size
  1766.         SUB    CL,DL        ;Subtract current position
  1767.         JCXZ    NO_CLEAR
  1768. ERASE_LOOP:
  1769.         MOV    AL," "        ;Write blanks to erase
  1770.         CALL    WRITE_NORMAL    ;Display it
  1771.         LOOP    ERASE_LOOP
  1772. NO_CLEAR:    POP DX
  1773.         RET
  1774. ERASE_EOL    ENDP
  1775.  
  1776. ;-----------------------------------------------------------------------
  1777. ; This outputs a message (pointed to by SI) and waits for a Y/N
  1778. ; response. If 'N' the prompt line is restored and a ZF is cleared
  1779. ; is returned. Otherwise ZF is set on return
  1780. ;-----------------------------------------------------------------------
  1781. ASK_STRING    PROC    NEAR
  1782.         ASSUME    DS:CSEG
  1783.         PUSH    DS
  1784.         PUSH    CS
  1785.         POP    DS
  1786.         MOV    DH,ROWS    ;Last row on display
  1787.         INC    DH        ;Bottom row of screen
  1788.         XOR    DL,DL        ;First column
  1789.         MOV    DH,ROWS    ;Move to last row on screen
  1790.         INC    DH
  1791.         XOR    DL,DL        ;And column zero
  1792.         CALL    TTY_STRING
  1793.         MOV    AH,KEYREAD_CODE
  1794.         INT    16H        ;Get character from keyboard
  1795.         CMP    AL,"Y"    ; Abort only if confirmed
  1796.         JE    ASK_RETURNS_YES
  1797.         CMP    AL,"y"
  1798. ASK_RETURNS_YES:
  1799.         PUSHF            ;Save the result status
  1800.         CALL    REDO_PROMPT
  1801.         POPF
  1802.         POP    DS
  1803.         RET
  1804. ASK_STRING    ENDP
  1805.  
  1806. ;-----------------------------------------------------------------------
  1807. ; This outputs a message (pointed to by SI), adds a prompt
  1808. ; and then waits for a response.  The prompt line is then restored.
  1809. ;-----------------------------------------------------------------------
  1810. ERROR_MESG    PROC    NEAR
  1811.         ASSUME    DS:CSEG
  1812.         PUSH    DS
  1813.         PUSH    CS
  1814.         POP    DS
  1815.         MOV    DH,ROWS    ;Last row on display
  1816.         INC    DH    ;Bottom row of screen
  1817.         XOR    DL,DL    ;First column
  1818.         MOV    DH,ROWS    ;Move to last row on screen
  1819.         INC    DH
  1820.         XOR    DL,DL        ;And column zero
  1821.         CALL    TTY_STRING    ;Output error message
  1822.         MOV    SI,OFFSET PAD_MESS
  1823.         CALL    TTY_STRING
  1824.         MOV    SI,OFFSET CONTINUE_MESS
  1825.         CALL    TTY_STRING
  1826.         MOV    AH,KEYREAD_CODE
  1827.         INT    16H        ;Get character from keyboard
  1828.         CALL    REDO_PROMPT
  1829.         POP    DS
  1830.         RET
  1831. ERROR_MESG    ENDP
  1832.  
  1833. ;-----------------------------------------------------------------------
  1834. ; This displays the function key prompt, word wrap and insert mode state
  1835. ;-----------------------------------------------------------------------
  1836. REDO_PROMPT    PROC    NEAR
  1837.         ASSUME    DS:NOTHING, ES:NOTHING
  1838.         PUSH    DS
  1839.         PUSH    CS
  1840.         POP    DS
  1841.         ASSUME    DS:CSEG
  1842.         MOV    DH,ROWS        ;Put prompt at last row
  1843.         INC    DH
  1844.         XOR    DL,DL        ;And column 0
  1845.         CALL    POSITION    ;Convert to screen offset
  1846.         MOV    SI,OFFSET PROMPT_STRING
  1847. KEY_LOOP:
  1848.         MOV    AL,"F"        ;Display an "F"
  1849.         CALL    WRITE_NORMAL
  1850.         LODSB
  1851.         OR    AL,AL        ;Last key in prompt?
  1852.         JZ    PROMPT_DONE
  1853.         CALL    WRITE_NORMAL
  1854.  
  1855.         CMP    BYTE PTR CS:[SI],"0"    ;Is it F10?
  1856.         JNE    TEXT_LOOP
  1857.         LODSB
  1858.         CALL    WRITE_NORMAL
  1859. TEXT_LOOP:
  1860.         LODSB
  1861.         OR    AL,AL        ;Last letter in word?
  1862.         JNZ    WRITE_CHAR
  1863.  
  1864.         MOV    AL," "        ;Display a space
  1865.         CALL    WRITE_NORMAL
  1866.         JMP    KEY_LOOP
  1867. WRITE_CHAR:
  1868.         CALL    WRITE_INVERSE    ;Display the letter
  1869.         JMP    TEXT_LOOP    ;Do the next letter
  1870. PROMPT_DONE:
  1871.         MOV    DH,ROWS
  1872.         INC    DH        ;Get to last row on screen
  1873.         MOV    DL,PROMPT_LENGTH + 9
  1874.         CALL    ERASE_EOL    ;Erase to the end of this row
  1875.         DEC    DI        ;Backup two character positions
  1876.         DEC    DI
  1877.         DEC    DI
  1878.         DEC    DI
  1879.         MOV    AL," "        ;indicates no word wrap
  1880.         CMP    WRAP_FLAG,0    ;test word wrap flag
  1881.         JE    NO_WRAP
  1882.         MOV    AL,"W"        ;indicate word wrap on
  1883. NO_WRAP:
  1884.         CALL    WRITE_NORMAL
  1885.         MOV    AL,"O"        ;Write an "O"
  1886.         CMP    INSERT_MODE,0    ;In insert mode?
  1887.         JE    OVERSTRIKE
  1888.         MOV    AL,"I"        ;Write an "I"
  1889. OVERSTRIKE:
  1890.         CALL    WRITE_NORMAL
  1891.         POP    DS
  1892.         RET
  1893. REDO_PROMPT    ENDP
  1894.  
  1895. ;-----------------------------------------------------------------------
  1896. ; This displays the file buffer on the screen.
  1897. ;-----------------------------------------------------------------------
  1898. DISPLAY_SCREEN    PROC    NEAR
  1899.         ASSUME    DS:FILE_SEG, ES:FILE_SEG
  1900.         MOV    SI,TOP_OF_SCREEN;Point to first char on screen
  1901.         XOR    DH,DH        ;Start at first row
  1902.         JMP    SHORT NEXT_ROW
  1903. DISPLAY_BOTTOM:                ;This redraws the bottom only
  1904.         CALL    FIND_START    ;Find first character on this row
  1905.         MOV    DX,CUR_POSN    ;Get current cursor row
  1906. NEXT_ROW:
  1907.         PUSH    DX
  1908.         CALL    DISPLAY_LINE    ;Display a line
  1909.         POP    DX
  1910.         INC    DH        ;Move to the next row
  1911.         CMP    DH,ROWS        ;At end of screen yet?
  1912.         JBE    NEXT_ROW    ;Do all the rows
  1913.         RET
  1914. DISPLAY_SCREEN    ENDP
  1915.  
  1916. ;-----------------------------------------------------------------------
  1917. ; This subroutine displays a single line to the screen. DH holds the 
  1918. ; row number, SI has the offset into the file buffer. Tabs are expanded.
  1919. ; Adjustment is made for side shift.
  1920. ;-----------------------------------------------------------------------
  1921. DISPLAY_CURRENT    PROC    NEAR
  1922.         CALL    FIND_START
  1923.         MOV    DX,CUR_POSN
  1924. DISPLAY_LINE:
  1925.         XOR    DL,DL        ;Start at column zero
  1926.         MOV    MARGIN_COUNT,DL
  1927.         MOV    CX,DX        ;Use CL to count the columns
  1928.         CALL    POSITION    ;Compute offset into video
  1929. NEXT_CHAR:
  1930.         CMP    SI,LAST_CHAR    ;At end of file?
  1931.         JAE    LINE_DONE
  1932.         LODSB            ;Get next character
  1933.         CMP    AL,CR        ;Is it a carriage return?
  1934.         JE    FOUND_CR    ;Quit when a CR is found
  1935.         CMP    AL,TAB        ;Is this a Tab character
  1936.         JE    EXPAND_TAB    ;If yes, expand to spaces
  1937. DO_PUT:
  1938.         CALL    PUT_CHAR    ;Put character onto screen
  1939. TAB_DONE:
  1940.         CMP    CL,COLUMNSB    ;At right edge of screen?
  1941.         JB    NEXT_CHAR
  1942. LN_OVF:
  1943.         CMP    SI,LAST_CHAR    ;At end of file?
  1944.         JAE    NOT_BEYOND
  1945.         CMP    BYTE PTR [SI],CR
  1946.         JNE    DO_DIA
  1947.         INC     SI
  1948.         CMP    SI,LAST_CHAR    ;At end of file?
  1949.         JAE    NOT_BEYOND
  1950.         CMP    BYTE PTR [SI],LF;Is this the end of the line?
  1951.         JNE    DO_DIA
  1952.         DEC    SI
  1953.         JMP    FIND_NEXT
  1954. DO_DIA:        DEC    DI        ;Backup one character
  1955.         DEC    DI
  1956.         MOV    AL,4        ;Show a diamond
  1957.         CALL    WRITE_INVERSE    ;In inverse video
  1958. NOT_BEYOND:
  1959.         JMP    FIND_NEXT    ;Find start of next line
  1960. FOUND_CR:
  1961.         LODSB            ;Look at the next character
  1962.         CMP    AL,LF        ;Is it a line feed?
  1963.         JE    LINE_DONE
  1964.         MOV    AL,CR
  1965.         DEC    SI
  1966.         JMP    SHORT DO_PUT
  1967. LINE_DONE:
  1968.         MOV    DX,CX
  1969.         JMP    ERASE_EOL    ;Erase the rest of the line
  1970. EXPAND_TAB:
  1971.         MOV    AL," "        ;Convert Tabs to spaces
  1972.         CALL    PUT_CHAR
  1973.         MOV    AL,MARGIN_COUNT
  1974.         ADD    AL,CL
  1975.         TEST    AL,00000111B    ;At even multiple of eight?
  1976.         JNZ    EXPAND_TAB    ;If not keep adding spaces
  1977.         JMP    TAB_DONE
  1978. DISPLAY_CURRENT    ENDP
  1979.  
  1980. ;-----------------------------------------------------------------------
  1981. ; This displays a single character to the screen.  If the character is 
  1982. ; marked, it is shown in inverse video.  Characters outside the current
  1983. ; margin are not displayed. Characters left of the margin are skipped.
  1984. ;-----------------------------------------------------------------------
  1985. PUT_CHAR    PROC    NEAR
  1986.         MOV    BL,MARGIN_COUNT    ;Get distance to left margin
  1987.         CMP    BL,LEFT_MARGIN    ;Are we inside left margin?
  1988.         JAE    IN_WINDOW    ;If yes, show the character
  1989.         INC    BL
  1990.         MOV    MARGIN_COUNT,BL
  1991.         RET
  1992. IN_WINDOW:    CMP    SRCH_FLG,0
  1993.         JE    CKM
  1994.         CMP    SI,CURSOR
  1995.         JBE    CKM
  1996.         CMP    SI,SRCH_STR_END
  1997.         JA    CKM
  1998.         CALL    WRITE_FIND
  1999.         JMP    SHORT NEXT_COL
  2000. CKM:
  2001.         CMP    SI,MARK_START    ;Is this character marked?
  2002.         JBE    NOT_MARKED
  2003.         CMP    SI,MARK_END
  2004.         JA    NOT_MARKED
  2005.         CALL    WRITE_INVERSE    ;Marked characters shown inverse
  2006.         JMP    SHORT NEXT_COL
  2007. NOT_MARKED:
  2008.         CALL    WRITE_NORMAL
  2009. NEXT_COL:
  2010.         INC    CL        ;Increment the column count
  2011.         RET
  2012. PUT_CHAR    ENDP
  2013.  
  2014. ;-----------------------------------------------------------------------
  2015. ; This routine adds a character into the file.  In insert mode, remaining
  2016. ; characters are pushed forward. If a CR is inserted, a LF is added also.
  2017. ;-----------------------------------------------------------------------
  2018. INSERT_KEY    PROC    NEAR
  2019.         MOV    SI,CURSOR
  2020.         CMP    AL,CR        ;Was this a carriage return
  2021.         JNE    CK_INS
  2022.         CMP    AH,1CH
  2023.         JNE    CK_INS
  2024.         JMP    NEW_LINE
  2025. CK_INS:
  2026.         MOV    SI,CURSOR
  2027.         CMP    INSERT_MODE,0    ;In insert mode?
  2028.         JNE    INSERT_CHAR
  2029.         CMP    SI,LAST_CHAR    ;At end of file?
  2030.         JE    INSERT_CHAR
  2031.         CMP    BYTE PTR [SI],CR
  2032.         INC    SI
  2033.         CMP    SI,LAST_CHAR    ;At end of file?
  2034.         DEC    SI
  2035.         JE    INSERT_CHAR
  2036.         CMP    BYTE PTR [SI+1],LF;At end of line?
  2037.         JE    INSERT_CHAR
  2038.         MOV    DI,SI
  2039.         XCHG    DS:[SI],AL    ;Switch new character for old one
  2040.         CALL    SAVE_CHAR    ;Store the old character
  2041.         JMP    SHORT ADVANCE
  2042. INSERT_CHAR:
  2043.         PUSH    SI
  2044.         PUSH    AX        ;Save the new character
  2045.         MOV    AX,1
  2046.         CALL    OPEN_SPACE    ;Make room for it
  2047.         POP    AX        ;Get back the new character
  2048.         POP    DI
  2049.         JC    FILE_FULL
  2050.         STOSB            ;Insert character in file buffer
  2051. ADVANCE:
  2052.         OR    DIRTY_BITS,4    ;Current line is dirty
  2053.         PUSH    UNDO_LENGTH
  2054.         CALL    RIGHT        ;Move cursor to next letter
  2055.         POP    UNDO_LENGTH
  2056.         CMP    WRAP_FLAG,0    ;Word Wrap on?
  2057.         JE    FILE_FULL    ;Skip if not
  2058.         CALL    WRAP
  2059. FILE_FULL:
  2060.         RET
  2061. NEW_LINE:
  2062.         PUSH    SI
  2063.         MOV    AX,2
  2064.         CALL    OPEN_SPACE    ;Make space for CR and LF
  2065.         POP    DI        ;Get back old cursor location
  2066.         JC    FILE_FULL
  2067.         MOV    AX,LF*256+CR
  2068.         STOSW            ;Store the CR and LF
  2069.         CALL    DISPLAY_BOTTOM    ;Repaint bottom of the screen
  2070.         CALL    HOME        ;Cursor to start of line
  2071.         JMP    DOWN        ;Move down to the new line
  2072. INSERT_KEY    ENDP
  2073.  
  2074.  
  2075. ;-----------------------------------------------------------------------
  2076. ; This subroutine performs line wrap and paragraph
  2077. ; reformatting
  2078. ;-----------------------------------------------------------------------
  2079. WRAP        PROC    NEAR
  2080.         PUSH    CURSOR
  2081.         CALL    FORMAT_LINE
  2082.         POP    SI
  2083.         JNC    END_WRAP    ;Skip if no split
  2084.         PUSH    CURSOR
  2085.         PUSH    CUR_POSN
  2086.         CMP    SI,CURSOR    ;has cursor been advanced
  2087.         JB    ADV_AGAIN
  2088.         MOV    SI,CURSOR
  2089.         CALL    FIND_NEXT
  2090.         MOV    CURSOR,SI
  2091. ADV_AGAIN:
  2092.         CALL    JOIN_LINES
  2093.         JC    ADV_END
  2094.         CALL    FORMAT_LINE
  2095.         JNC    ADV_END
  2096. ADV_2:
  2097.         MOV    SI,CURSOR
  2098.         CALL    FIND_EOL
  2099.         MOV    CURSOR,SI
  2100.         JMP    SHORT ADV_AGAIN
  2101. ADV_END:
  2102.         CALL    FORMAT_LINE        ;last line shorter than screen width?
  2103.         JC    ADV_2
  2104.         POP    CUR_POSN
  2105.         POP    CURSOR
  2106.         MOV    DX,CUR_POSN
  2107.         MOV    SI,CURSOR
  2108.         CALL    LOCATE
  2109. END_WRAP:
  2110.         RET
  2111. WRAP        ENDP
  2112. ;-----------------------------------------------------------------------
  2113. ; This subroutine inserts spaces into the file buffer.  On entry AX
  2114. ; contains the number of spaces to be inserted.  On return, CF=1 if
  2115. ; there was not enough space in the file buffer.
  2116. ;-----------------------------------------------------------------------
  2117. OPEN_SPACE    PROC    NEAR
  2118.         MOV    CX,LAST_CHAR    ;Last character in the file
  2119.         MOV    SI,CX
  2120.         MOV    DI,CX
  2121.         ADD    DI,AX        ;Offset for new end of file
  2122.         JC    NO_ROOM        ;If no more room, return error
  2123.         MOV    LAST_CHAR,DI    ;Save offset of end of file
  2124.         SUB    CX,CURSOR    ;Number of characters to shift
  2125.         DEC    DI
  2126.         DEC    SI
  2127.         STD            ;String moves goes forward
  2128.         REP    MOVSB        ;Shift the file upward
  2129.         CLD
  2130.         CLC
  2131. NO_ROOM:
  2132.         RET
  2133. OPEN_SPACE    ENDP
  2134.  
  2135. ;-----------------------------------------------------------------------
  2136. ; This subroutine adjusts the cursor position ahead to the saved cursor
  2137. ; column.  On entry DH has the cursor row.
  2138. ;-----------------------------------------------------------------------
  2139. SHIFT_RIGHT    PROC    NEAR
  2140.         MOV    CL,SAVE_COLUMN    ;Keep the saved cursor offset
  2141.         XOR    CH,CH
  2142.         MOV    BP,CX        ;Keep the saved cursor position
  2143.         ADD    CL,LEFT_MARGIN    ;Shift into visable window also
  2144.         ADC    CH,0
  2145.         XOR    DL,DL
  2146.         MOV    CUR_POSN,DX    ;Get cursor row/column
  2147.         JCXZ    NO_CHANGE
  2148. RIGHT_AGAIN:
  2149.         PUSH    CX
  2150.         CMP    BYTE PTR [SI],CR;At end of line?
  2151.         JE    DONT_MOVE    ;If at end, stop moving
  2152.         CALL    RIGHT        ;Move right one character
  2153. DONT_MOVE:
  2154.         POP    CX
  2155.  
  2156.         MOV    AL,SAVE_COLUMN
  2157.         XOR    AH,AH
  2158.         CMP    AX,CX        ;Is cursor still in margin?
  2159.         JL    IN_MARGIN    ;If yes, keep moving
  2160.  
  2161.         MOV    DX,CUR_POSN    ;Get cursor column again
  2162.         XOR    DH,DH
  2163.         CMP    DX,BP        ;At saved cursor position?
  2164.         JE    RIGHT_DONE    ;If yes, were done
  2165.         JA    RIGHT_TOO_FAR    ;Did we go too far?
  2166. IN_MARGIN:
  2167.         LOOP    RIGHT_AGAIN
  2168. RIGHT_DONE:
  2169.         MOV    CX,BP
  2170.         MOV    SAVE_COLUMN,CL    ;Get back saved cursor position
  2171. NO_CHANGE:
  2172.         RET
  2173. RIGHT_TOO_FAR:
  2174.         CALL    LEFT        ;Move back left one place
  2175.         MOV    CX,BP
  2176.         MOV    SAVE_COLUMN,CL    ;Get back saved cursor position
  2177.         RET
  2178. SHIFT_RIGHT    ENDP
  2179.  
  2180. ;-----------------------------------------------------------------------
  2181. ; This subroutine skips past the CR and LF at SI.  SI returns new offset
  2182. ;-----------------------------------------------------------------------
  2183. SKIP_CR_LF    PROC    NEAR
  2184.         CMP    SI,LAST_CHAR    ;At last char in the file?
  2185.         JAE    NO_SKIP        ;If yes, dont skip anything
  2186.         CMP    BYTE PTR [SI],CR;Is first character a CR?
  2187.         JNE    NO_SKIP
  2188.         INC    SI        ;Look at next character
  2189.         CMP    SI,LAST_CHAR    ;Is it at the end of file?
  2190.         JAE    NO_SKIP        ;If yes, dont skip anymore
  2191.         CMP    BYTE PTR [SI],LF;Is next character a line feed?
  2192.         JNE    NO_SKIP        ;Skip any line feeds also
  2193.         INC    SI
  2194. NO_SKIP:
  2195.         RET
  2196. SKIP_CR_LF    ENDP
  2197.  
  2198. ;-----------------------------------------------------------------------
  2199. ; This subroutine finds the beginning of the previous line.
  2200. ;-----------------------------------------------------------------------
  2201. FIND_PREVIOUS    PROC    NEAR
  2202.         PUSH    CURSOR        ;Save the cursor location
  2203.         CALL    FIND_CR        ;Find start of this line
  2204.         MOV    CURSOR,SI    ;Save the new cursor
  2205.         CALL    FIND_START    ;Find the start of this line
  2206.         POP    CURSOR        ;Get back starting cursor
  2207.         RET
  2208. FIND_PREVIOUS    ENDP
  2209.  
  2210. ;-----------------------------------------------------------------------
  2211. ; This searches for the previous carriage return.  Search starts at SI.
  2212. ;-----------------------------------------------------------------------
  2213. FIND_CR        PROC    NEAR
  2214.         PUSH    CX
  2215.         MOV    AL,LF        ;Look for a carriage return
  2216.         MOV    DI,SI
  2217.         MOV    CX,SI
  2218.         JCXZ    AT_BEGINNING
  2219.         DEC    DI
  2220.         STD            ;Search backwards
  2221. LF_PREV:
  2222.         REPNE    SCASB        ;Scan for the character
  2223.         JCXZ    LF_END
  2224.         CMP    BYTE PTR [DI],CR
  2225.         JNE    LF_PREV
  2226.         DEC    DI
  2227. LF_END:
  2228.         CLD            ;Restore direction flag
  2229.         INC    DI
  2230.         MOV    SI,DI
  2231. AT_BEGINNING:
  2232.         POP    CX
  2233.         RET
  2234. FIND_CR        ENDP
  2235.  
  2236. ;-----------------------------------------------------------------------
  2237. ; This subroutine computes the location of the start of current line.
  2238. ; Returns SI pointing to the first character of the current line.
  2239. ;-----------------------------------------------------------------------
  2240. FIND_START    PROC    NEAR
  2241.         MOV    SI,CURSOR    ;Get the current cursor
  2242.         OR    SI,SI        ;At start of the file?
  2243.         JZ    AT_START    ;If yes, were done
  2244.         CALL    FIND_CR        ;Find the 
  2245.         CALL    SKIP_CR_LF
  2246. AT_START:
  2247.         RET
  2248. FIND_START    ENDP
  2249.  
  2250. ;-----------------------------------------------------------------------
  2251. ; This finds the offset of the start of the next line.  The search is 
  2252. ; started at location ES:SI.  On return CF=1 of no CR was found.
  2253. ;-----------------------------------------------------------------------
  2254. FIND_NEXT    PROC    NEAR
  2255.         PUSH    CX
  2256.         CALL    FIND_EOL    ;Find the end of this line
  2257.         JC    AT_NEXT        ;If at end of file, return
  2258.         CALL    SKIP_CR_LF    ;Skip past CR and LF
  2259.         CLC            ;Indicate end of line found
  2260. AT_NEXT:                  
  2261.         POP    CX
  2262.         RET
  2263. FIND_NEXT    ENDP
  2264.  
  2265. ;-----------------------------------------------------------------------
  2266. ; This finds the offset of the start of the next paragraph. The search
  2267. ; starts at ES:SI. On return CF=1 if no CR was found
  2268. ;-----------------------------------------------------------------------
  2269. FIND_NEXT_PARA    PROC    NEAR
  2270.         CALL    FIND_NEXT        ;Goto start of next line
  2271.         JC    FNP_EOF
  2272. FNP_LOOP:
  2273.         CMP    SI,LAST_CHAR    ;At end of file?
  2274.         JNB    FNP_EOF
  2275.         LODSB                ;Get next character
  2276.         CMP    AL," "        ;Is it a space?
  2277.         JE    FNP_LOOP
  2278.         CMP    AL,TAB        ;Is it a TAB?
  2279.         JE    FNP_LOOP
  2280.         CMP    AL,CR
  2281.         JNE    FIND_NEXT_PARA
  2282.         CMP    SI,LAST_CHAR    ;At end of file?
  2283.         JNB    FNP_EOF
  2284.         LODSB
  2285.         CMP    AL,LF
  2286.         JNE    FIND_NEXT_PARA
  2287. ;Now look next non-white space graphic
  2288. FNP_LOOP2:
  2289.         CMP    SI,LAST_CHAR    ;At end of file?
  2290.         JNB    FNP_EOF
  2291.         LODSB
  2292. FNP_LOOP3:
  2293.         CMP    AL," "
  2294.         JE    FNP_LOOP2
  2295.         CMP    AL,TAB
  2296.         JE    FNP_LOOP2
  2297.         CMP    AL,CR
  2298.         JNE    FNP_DONE
  2299.         CMP    SI,LAST_CHAR    ;At end of file?
  2300.         JNB    FNP_EOF
  2301.         LODSB
  2302.         CMP    AL,LF
  2303.         JNE    FNP_LOOP3
  2304.         JMP    SHORT FNP_LOOP2
  2305. FNP_DONE:
  2306.         DEC    SI
  2307.         CLC
  2308.         RET
  2309. FNP_EOF:
  2310.         STC
  2311.         RET
  2312. FIND_NEXT_PARA    ENDP
  2313. ;-----------------------------------------------------------------------
  2314. ; This searches for the next carriage return in the file.  The search
  2315. ; starts at the offset in register SI.
  2316. ;-----------------------------------------------------------------------
  2317. FIND_EOL    PROC    NEAR
  2318.         MOV    AL,CR        ;Look for a carriage return
  2319. CR_SCAN:
  2320.         MOV    CX,LAST_CHAR    ;Last letter in the file
  2321.         SUB    CX,SI        ;Count for the search
  2322.         MOV    DI,SI
  2323.         JCXZ    AT_END        ;If nothing to search, return
  2324.         REPNE    SCASB        ;Scan for the character
  2325.         MOV    SI,DI        ;Return the location of the CR
  2326.         JCXZ    AT_END        ;If not found, return
  2327.         CMP    BYTE PTR [SI],LF
  2328.         JNE    CR_SCAN
  2329.         DEC    SI
  2330.         CLC            ;Indicate the CR was found
  2331.         RET
  2332. AT_END:
  2333.         STC            ;Indicate CR was not found
  2334.         RET
  2335. FIND_EOL    ENDP
  2336. ;-----------------------------------------------------------------------
  2337. ; This subroutine reformats the current line
  2338. ; and splits it so that the text fits on the screen
  2339. ; returns carry = 1 if line split
  2340. ;-----------------------------------------------------------------------
  2341. FORMAT_LINE    PROC    NEAR
  2342.         PUSH    UNDO_LENGTH
  2343. GET_LINE_LENGTH:
  2344.         CALL    FIND_START    ;SI now points to start of line
  2345.         PUSH    SI
  2346.         CALL    FIND_EOL
  2347.         MOV    BX,SI        ;BX now points to CR at EOL
  2348.         POP    SI
  2349.         PUSH    ES
  2350.         PUSH    CS
  2351.         POP    ES
  2352.         ASSUME    ES:CSEG
  2353.         XOR    CX,CX        ;CX to hold line length
  2354.         MOV    LAST_WORD,SI    ;save position of first word in line
  2355.         MOV    INDENT_SIZE,0
  2356.         MOV    DI,OFFSET INDENT_BUFFER
  2357. LOOP_TO_WORD:
  2358.         CMP    SI,BX        ;End of Line?
  2359.         JAE    INDENT_END
  2360.         LODSB
  2361.         CMP    AL,TAB        ;Is this a TAB?
  2362.         JNE    NOT_LEADING_TAB
  2363.         AND    CL,0F8H        ;Mask to round down to multiple of 8
  2364.         ADD    CX,8        ;Add tab count (tabs EVERY 8 CHARS)
  2365.         JMP    SHORT STORE_INDENT
  2366. NOT_LEADING_TAB:
  2367.         INC    CX
  2368.         CMP    AL," "        ;is it a space?
  2369.         JNE    INDENT_END
  2370. STORE_INDENT:
  2371.         CMP    CL,MAX_INDENT    ;check for overflow
  2372.         JA    LOOP_TO_WORD
  2373.         STOSB            ;store in indent buffer
  2374.         INC    INDENT_SIZE
  2375.         JMP    SHORT LOOP_TO_WORD
  2376. INDENT_END:
  2377.         POP    ES
  2378.         ASSUME    ES:NOTHING
  2379.  
  2380. NEW_WORD:
  2381.         MOV    AX,WCOLUMNS
  2382.         INC    AX
  2383.         CMP    CX,AX        ;Past right edge of screen?
  2384.         JA    LOOP_END_WORD
  2385.         MOV    AX,SI
  2386.         DEC    AX
  2387.         MOV    LAST_WORD,AX    ;Save position of start of this word
  2388. LOOP_END_WORD:
  2389.         CMP    SI,BX        ;End of Line?
  2390.         JAE    EOL_FOUND
  2391.         LODSB
  2392.         CMP    AL,TAB        ;Is it a TAB?
  2393.         JNE    NOT_TAB
  2394.         AND    CL,0F8H        ;Mask to round down to multiple of 8
  2395.         ADD    CX,8        ;Add tab count (tabs EVERY 8 CHARS)
  2396.         JMP    SHORT END_OF_WORD
  2397. NOT_TAB:
  2398.         INC    CX
  2399.         CMP    AL," "        ;Is it a space?
  2400.         JE    END_OF_WORD
  2401.         CMP    AL,"-"        ;Is it  Hyphen
  2402.         JNE    LOOP_END_WORD
  2403. END_OF_WORD:
  2404.         PUSH    CX
  2405. LOOP_TO_NEXT_WORD:
  2406.         CMP    SI,BX        ;End of Line?
  2407.         JAE    SPACE_AT_EOL
  2408.         LODSB
  2409.         CMP    AL,TAB        ;Is it a TAB?
  2410.         JNE    NOT_TRAILING_TAB
  2411.         AND    CL,0F8H        ;Mask to round down to multiple of 8
  2412.         ADD    CX,8        ;Add tab count (tabs EVERY 8 CHARS)
  2413.         JMP    SHORT LOOP_TO_NEXT_WORD
  2414. NOT_TRAILING_TAB:
  2415.         INC    CX
  2416.         CMP    AL," "        ;Is it a space?
  2417.         JE    LOOP_TO_NEXT_WORD
  2418.         POP    AX            ;Adjust stack
  2419.         JMP    SHORT NEW_WORD
  2420. SPACE_AT_EOL:
  2421.         POP    AX            ;Get line size at entry to last loop
  2422.         CMP    AX,WCOLUMNS        ;Past right edge of screen
  2423.         JBE    FORMAT_END
  2424. EOL_FOUND:
  2425.         CMP    CX,WCOLUMNS    ;Is line longer than screen width?
  2426.         JA    WORD_WRAP    ;then reformat
  2427. FORMAT_END:
  2428.         POP    UNDO_LENGTH
  2429.         CLC
  2430.         RET
  2431.  
  2432. WORD_WRAP:
  2433.         MOV    AX,SI
  2434.         SUB    AX,LAST_WORD    ;How long is last word?
  2435.         CMP    AX,CX        ;As long as line?
  2436.         JGE    FORMAT_END    ;Cannot wrap words as long as line
  2437. ;insert CR/LF and indent at start of last word
  2438.         PUSH    SI
  2439.         PUSH    CURSOR
  2440.         MOV    DI,LAST_WORD
  2441.         MOV    CURSOR,DI
  2442.         MOV    AX,INDENT_SIZE
  2443.         ADD    AX,2        ;AX holds space requirement for CR/LF
  2444.                     ;and indent
  2445.         CMP    MARK_MODE,0
  2446.         JE    OPEN_UP
  2447.         CMP    DI,MARK_HOME
  2448.         JA    OPEN_UP    ;before mark_end
  2449.         MOV    BX,MARK_HOME
  2450.         ADD    BX,AX
  2451.         MOV    MARK_HOME,BX    ;then update mark end
  2452. OPEN_UP:
  2453.         PUSH    AX
  2454.         CALL    OPEN_SPACE    ;Make space for CR/LF
  2455.         POP    BX
  2456.         POP    CURSOR
  2457.         POP    SI
  2458.         JC    FORMAT_END    ;exit if no space
  2459.         ADD    SI,BX        ;update EOL pointer
  2460.         MOV    DI,LAST_WORD    ;DI = CR/LF insertion point
  2461.         MOV    AX,LF*256+CR
  2462.         STOSW            ;insert CR/LF
  2463.         MOV    CX,INDENT_SIZE
  2464.         JCXZ    NO_INDENT
  2465.         PUSH    SI
  2466.         MOV    SI,OFFSET INDENT_BUFFER
  2467.         PUSH    DS
  2468.         PUSH    CS
  2469.         POP    DS
  2470.         REP    MOVSB        ;Insert indent characters
  2471.         POP    DS
  2472.         POP    SI
  2473. NO_INDENT:
  2474.         MOV    DX,CUR_POSN
  2475.         MOV    DI,CURSOR
  2476.         CMP    DI,LAST_WORD    ;was CURSOR after insertion point?
  2477.         JB    ADJUST_EOL
  2478.         ADD    DI,BX        ;update CURSOR pointer
  2479.         MOV    CURSOR,DI
  2480.         CMP    DH,ROWS        ;Bottom of screen?
  2481.         JNB    ADJUST_EOL
  2482.         INC    DH        ;Otherwise, locate cursor on next row
  2483. ADJUST_EOL:
  2484.         MOV    SI,CURSOR
  2485.         CALL    LOCATE
  2486.         MOV    DIRTY_BITS,1    ;redraw screen
  2487.         POP    UNDO_LENGTH
  2488.         STC
  2489.         RET
  2490. FORMAT_LINE    ENDP
  2491. ;----------------------------------------------------------------------------
  2492. ; This subroutine deletes the current end of line (w.r.t. SI) and following 
  2493. ; white space unless it is end of paragraph as well
  2494. ;----------------------------------------------------------------------------
  2495. JOIN        PROC    NEAR
  2496.         CALL    JOIN_LINES
  2497.         CMP    WRAP_FLAG,0        ;wORD WRAP ON?
  2498.         JE    END_JOIN
  2499.         CALL    WRAP
  2500. END_JOIN:
  2501.         RET
  2502. JOIN        ENDP
  2503. ;-----------------------------------------------------------------------
  2504. ; Joins the current line only
  2505. ; returns with carry set if at EOP
  2506. ;--------------------------------------------------------------------------
  2507. JOIN_LINES    PROC    NEAR
  2508.         MOV    SI,CURSOR
  2509.         CALL    FIND_EOL    ;Advance SI to EOL
  2510.         JNC    JOIN_NOT_AT_TOF
  2511.         RET
  2512. JOIN_NOT_AT_TOF:
  2513.         MOV    DI,SI
  2514. DEL_EOL_SPACES:
  2515.         OR    DI,DI        ;Top of file?
  2516.         JZ    DEL_EOL_DONE
  2517.         DEC    DI
  2518.         CMP    BYTE PTR [DI]," "    ;Remove trailing space
  2519.         JE    DEL_EOL_SPACES
  2520.         CMP    BYTE PTR [DI],TAB    ;and TABs
  2521.         JE    DEL_EOL_SPACES
  2522.         INC    DI
  2523. DEL_EOL_DONE:
  2524. ;delete EOL marker and trailing white space
  2525.         MOV    CX,LAST_CHAR
  2526.         INC    SI
  2527.         INC    SI        ;move pass CR/LF
  2528. LOOP_PASSED_SPACES:
  2529.         CMP    SI,CX        ;at EOF?
  2530.         JNB    DEL_EOL_MARKER
  2531.         LODSB
  2532.         CMP    AL,CR        ;Is it a CR?
  2533.         JNE    TEST_FOR_SPACE
  2534.         CMP    SI,CX        ;at EOF?
  2535.         JNB    DEL_EOL_MARKER
  2536.         LODSB
  2537.         CMP    AL,LF        ;Is it a LF?
  2538.         JNE    TEST_FOR_SPACE
  2539.         STC            ;indicates EOP on exit
  2540.         RET
  2541. TEST_FOR_SPACE:
  2542.         CMP    AL," "        ;Loop to remove leading spaces
  2543.         JE    LOOP_PASSED_SPACES
  2544.         CMP    AL,TAB        ;and tabs
  2545.         JE    LOOP_PASSED_SPACES
  2546.         DEC    SI        ;step back
  2547. DEL_EOL_MARKER:
  2548.         SUB    CX,SI        ;Calculate no. of chars to move
  2549.         MOV    AX,CX
  2550.         ADD    AX,DI
  2551.         MOV    LAST_CHAR,AX    ;Adjust file length
  2552.         CMP    DI,CURSOR        ;CURSOR after deletion point?
  2553.         JA    CHECK_MARK_HOME
  2554.         MOV    CURSOR,DI        ;adjust CURSOR
  2555. CHECK_MARK_HOME:
  2556.         CMP    MARK_MODE,0            ;Text Marked?
  2557.         JE    DEL_WHITE_SPACE
  2558.         CMP    DI,MARK_HOME        ;MARK START after deletion?
  2559.         JA    DEL_WHITE_SPACE
  2560.         MOV    AX,SI
  2561.         SUB    AX,DI            ;Calculate no. of chars to shift up
  2562.         MOV    BX,MARK_HOME
  2563.         SUB    BX,AX            ;reduce MARK_START by deletion
  2564.         MOV    MARK_HOME,BX
  2565. DEL_WHITE_SPACE:
  2566.         PUSH    DI
  2567.         REP    MOVSB        ;Move file down one notch
  2568.         OR    DIRTY_BITS,2    ;bottom of screen is dirty
  2569.         POP    DI        ;get back old EOL pointer
  2570.         CMP    BYTE PTR [DI-1],"-"    ;is hyphen at old EOL?
  2571.         JE    JOIN_DONE
  2572.         MOV    AX,1            ;otherwise insert space
  2573.         PUSH    CURSOR
  2574.         MOV    CURSOR,DI
  2575.         PUSH    DI
  2576.         CALL    OPEN_SPACE
  2577.         POP    DI
  2578.         POP    CURSOR
  2579.         JNC    JOIN_MOVED_UP
  2580.         RET
  2581. JOIN_MOVED_UP:
  2582.         CMP    DI,CURSOR
  2583.         JA    AND_MARK_HOME
  2584.         INC    CURSOR
  2585. AND_MARK_HOME:
  2586.         CMP    MARK_MODE,0            ;Text Marked?
  2587.         JE    ADD_SPACE
  2588.         CMP    DI,MARK_HOME
  2589.         JA    ADD_SPACE
  2590.         INC    MARK_HOME
  2591. ADD_SPACE:
  2592.         MOV    AL," "
  2593.         STOSB
  2594. JOIN_DONE:
  2595.         CLC            ;Indicates not EOP
  2596.         RET
  2597. JOIN_LINES    ENDP
  2598.  
  2599. ;-----------------------------------------------------------------------
  2600. ; This subroutine positions the screen with the cursor at the row
  2601. ; selected in register DH.  On entry, SI holds the cursor offset.
  2602. ;-----------------------------------------------------------------------
  2603. LOCATE        PROC    NEAR
  2604.         MOV    CL,DH
  2605.         XOR    CH,CH
  2606.         MOV    CURSOR,SI
  2607.         XOR    DX,DX        ;Start at top of the screen
  2608.         OR    SI,SI        ;At start of buffer?
  2609.         JZ    LOCATE_FIRST
  2610.  
  2611.         CALL    FIND_START    ;Get start of this row
  2612.         XOR    DX,DX        ;Start at top of the screen
  2613.         OR    SI,SI        ;Is cursor at start of file?
  2614.         JZ    LOCATE_FIRST
  2615.         JCXZ    LOCATE_FIRST    ;If locating to top row were done
  2616. FIND_TOP:
  2617.         PUSH    SI
  2618.         PUSH    CX
  2619.         CALL    FIND_CR        ;Find previous row
  2620.         POP    CX
  2621.         POP    AX
  2622.         CMP    BYTE PTR [SI],CR
  2623.         JNE    LOCATE_FIRST
  2624.         CMP    BYTE PTR [SI+1],LF
  2625.         JNE    LOCATE_FIRST
  2626.         CMP    SI,AX        ;Did it change?
  2627.         JE    LOCATE_DONE    ;If not, quit moving
  2628.         INC    DH        ;Cursor moves to next row
  2629.         LOOP    FIND_TOP
  2630.  
  2631. LOCATE_DONE:
  2632.         PUSH    CURSOR
  2633.         MOV    CURSOR,SI
  2634.         CALL    FIND_START    ;Find start of top of screen
  2635.         POP    CURSOR
  2636. LOCATE_FIRST:
  2637.         MOV    TOP_OF_SCREEN,SI
  2638.         MOV    CUR_POSN,DX
  2639.         CALL    CURSOR_COL
  2640.         MOV    SAVE_COLUMN,DL
  2641.         RET
  2642. LOCATE        ENDP
  2643.  
  2644. ;-----------------------------------------------------------------------
  2645. ; This subroutine computes the correct column for the cursor.  No
  2646. ; inputs.  On exit, CUR_POSN is set and DX has the row/column.
  2647. ;-----------------------------------------------------------------------
  2648. CURSOR_COL    PROC    NEAR
  2649.         MOV    SI,CURSOR    ;Get cursor offset
  2650.         CALL    FIND_START    ;Find start of this line
  2651.         MOV    CX,CURSOR
  2652.         SUB    CX,SI
  2653.         MOV    DX,CUR_POSN    ;Get current row
  2654.         XOR    DL,DL        ;Start at column zero
  2655.         MOV    MARGIN_COUNT,DL    ;Count past the left margin
  2656.         JCXZ    COL_DONE
  2657. CURSOR_LOOP:
  2658.         LODSB            ;Get the next character
  2659.         CMP    AL,CR        ;Is it the end of line?
  2660.         JNE    NOT_EOL
  2661.         CMP    BYTE PTR [SI],LF
  2662.         JE    COL_DONE    ;If end, were done
  2663. NOT_EOL:
  2664.         CMP    AL,TAB        ;Is it a tab?
  2665.         JNE    NOT_A_TAB
  2666.  
  2667.         MOV    BL,MARGIN_COUNT
  2668.         OR    BL,00000111B
  2669.         MOV    MARGIN_COUNT,BL
  2670.         CMP    BL,LEFT_MARGIN    ;Inside visible window yet?
  2671.         JB    NOT_A_TAB    ;If not, don't advance cursor
  2672.         OR    DL,00000111B    ;Move to multiple of eight
  2673. NOT_A_TAB:
  2674.         MOV    BL,MARGIN_COUNT
  2675.         INC    BL
  2676.         MOV    MARGIN_COUNT,BL
  2677.         CMP    BL,LEFT_MARGIN
  2678.         JBE    OUT_OF_WINDOW
  2679.         INC    DL        ;Were at next column now
  2680. OUT_OF_WINDOW:
  2681.         LOOP    CURSOR_LOOP
  2682. COL_DONE:
  2683.         CMP    DL,COLUMNSB    ;Past end of display?
  2684.         JB    COLUMN_OK    ;If not, were OK?
  2685.         MOV    DL,COLUMNSB
  2686.         DEC    DL        ;Leave cursor at last column
  2687. COLUMN_OK:
  2688.         MOV    CUR_POSN,DX    ;Store the row/column
  2689.         RET
  2690. CURSOR_COL    ENDP
  2691.  
  2692. ;-----------------------------------------------------------------------
  2693. ; This displays the string at CS:SI at the location in DX.  The 
  2694. ; remainder of the row is erased.  Cursor is put at the end of the line.
  2695. ;-----------------------------------------------------------------------
  2696. TTY_STRING    PROC    NEAR
  2697.         ASSUME    DS:CSEG
  2698.         PUSH    DX
  2699.         CALL    POSITION    ;Compute offset into video
  2700.         POP    DX
  2701. TTY_LOOP:
  2702.         LODSB
  2703.         OR    AL,AL        ;At end of string yet?
  2704.         JZ    TTY_DONE
  2705.         INC    DL
  2706.         PUSH    DX
  2707.         CALL    WRITE_INVERSE    ;Write in inverse video
  2708.         POP    DX
  2709.         JMP    TTY_LOOP
  2710. TTY_DONE:
  2711.         CALL    SET_CURSOR    ;Move cursor to end of string
  2712.         JMP    ERASE_EOL    ;Erase the rest of line
  2713. TTY_STRING    ENDP
  2714.  
  2715. ;-----------------------------------------------------------------------
  2716. ; This copies the input filename to CS:DI and changes the extension
  2717. ;-----------------------------------------------------------------------
  2718. CHG_EXTENSION    PROC    NEAR
  2719.         ASSUME    DS:CSEG, ES:CSEG
  2720.  
  2721.         PUSH    SI
  2722.         MOV    SI,NAME_POINTER
  2723. CHG_LOOP:
  2724.         LODSB        
  2725.         CMP    AL,"."        ;Look for the extension
  2726.         JE    FOUND_DOT
  2727.         OR    AL,AL
  2728.         JZ    FOUND_DOT
  2729.         STOSB            ;Copy a character
  2730.         JMP    CHG_LOOP
  2731. FOUND_DOT:
  2732.         MOV    CX,5        ;Five chars in extension
  2733.         POP    SI
  2734.         REP    MOVSB        ;Move new extension in
  2735.         RET
  2736. CHG_EXTENSION    ENDP
  2737.  
  2738. ;-----------------------------------------------------------------------
  2739. ; This is the control break handler.  It ignores the break.
  2740. ;-----------------------------------------------------------------------
  2741. NEWINT23    PROC    FAR
  2742.         ASSUME    DS:NOTHING, ES:NOTHING
  2743.         MOV    CS:DIRTY_BITS,1
  2744.         CLC            ;Tell DOS to ignore break
  2745.         IRET
  2746. NEWINT23    ENDP
  2747.  
  2748. ;-----------------------------------------------------------------------
  2749. ; This is the severe error handler.  It homes the cursor before 
  2750. ; processing the error.
  2751. ;-----------------------------------------------------------------------
  2752. NEWINT24    PROC    FAR
  2753.         ASSUME    DS:NOTHING, ES:NOTHING
  2754.         PUSHF
  2755.         PUSH    AX
  2756.         PUSH    BX
  2757.         PUSH    DX
  2758.         MOV    CS:DIRTY_BITS,1
  2759.         XOR    DX,DX
  2760.         CALL    SET_CURSOR    ;Put cursor at home
  2761.         POP    DX
  2762.         POP    BX
  2763.         POP    AX
  2764.         POPF
  2765.         JMP    CS:OLDINT24
  2766. NEWINT24    ENDP
  2767. ;-----------------------------------------------------------------------
  2768. EVEN
  2769. NAME_DOT_$$$    EQU    $
  2770. NAME_DOT_BAK    EQU    $ + 80H
  2771. UNDO_BUFFER    EQU    $ + 100H
  2772. LINE_BUFFER    EQU    $ + 200H
  2773. NEW_STACK    EQU    $ + 500H
  2774. CSEG        ENDS
  2775. ;-----------------------------------------------------------------------
  2776. FILE_SEG    SEGMENT
  2777. FILE_SEG    ENDS
  2778. END        START
  2779.  
  2780.